PyXR

c:\python24\lib \ compiler \ pycodegen.py



0001 import imp
0002 import os
0003 import marshal
0004 import struct
0005 import sys
0006 import types
0007 from cStringIO import StringIO
0008 
0009 from compiler import ast, parse, walk, syntax
0010 from compiler import pyassem, misc, future, symbols
0011 from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
0012 from compiler.consts import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,\
0013      CO_NESTED, CO_GENERATOR, CO_GENERATOR_ALLOWED, CO_FUTURE_DIVISION
0014 from compiler.pyassem import TupleArg
0015 
0016 # XXX The version-specific code can go, since this code only works with 2.x.
0017 # Do we have Python 1.x or Python 2.x?
0018 try:
0019     VERSION = sys.version_info[0]
0020 except AttributeError:
0021     VERSION = 1
0022 
0023 callfunc_opcode_info = {
0024     # (Have *args, Have **args) : opcode
0025     (0,0) : "CALL_FUNCTION",
0026     (1,0) : "CALL_FUNCTION_VAR",
0027     (0,1) : "CALL_FUNCTION_KW",
0028     (1,1) : "CALL_FUNCTION_VAR_KW",
0029 }
0030 
0031 LOOP = 1
0032 EXCEPT = 2
0033 TRY_FINALLY = 3
0034 END_FINALLY = 4
0035 
0036 def compileFile(filename, display=0):
0037     f = open(filename, 'U')
0038     buf = f.read()
0039     f.close()
0040     mod = Module(buf, filename)
0041     try:
0042         mod.compile(display)
0043     except SyntaxError:
0044         raise
0045     else:
0046         f = open(filename + "c", "wb")
0047         mod.dump(f)
0048         f.close()
0049 
0050 def compile(source, filename, mode, flags=None, dont_inherit=None):
0051     """Replacement for builtin compile() function"""
0052     if flags is not None or dont_inherit is not None:
0053         raise RuntimeError, "not implemented yet"
0054 
0055     if mode == "single":
0056         gen = Interactive(source, filename)
0057     elif mode == "exec":
0058         gen = Module(source, filename)
0059     elif mode == "eval":
0060         gen = Expression(source, filename)
0061     else:
0062         raise ValueError("compile() 3rd arg must be 'exec' or "
0063                          "'eval' or 'single'")
0064     gen.compile()
0065     return gen.code
0066 
0067 class AbstractCompileMode:
0068 
0069     mode = None # defined by subclass
0070 
0071     def __init__(self, source, filename):
0072         self.source = source
0073         self.filename = filename
0074         self.code = None
0075 
0076     def _get_tree(self):
0077         tree = parse(self.source, self.mode)
0078         misc.set_filename(self.filename, tree)
0079         syntax.check(tree)
0080         return tree
0081 
0082     def compile(self):
0083         pass # implemented by subclass
0084 
0085     def getCode(self):
0086         return self.code
0087 
0088 class Expression(AbstractCompileMode):
0089 
0090     mode = "eval"
0091 
0092     def compile(self):
0093         tree = self._get_tree()
0094         gen = ExpressionCodeGenerator(tree)
0095         self.code = gen.getCode()
0096 
0097 class Interactive(AbstractCompileMode):
0098 
0099     mode = "single"
0100 
0101     def compile(self):
0102         tree = self._get_tree()
0103         gen = InteractiveCodeGenerator(tree)
0104         self.code = gen.getCode()
0105 
0106 class Module(AbstractCompileMode):
0107 
0108     mode = "exec"
0109 
0110     def compile(self, display=0):
0111         tree = self._get_tree()
0112         gen = ModuleCodeGenerator(tree)
0113         if display:
0114             import pprint
0115             print pprint.pprint(tree)
0116         self.code = gen.getCode()
0117 
0118     def dump(self, f):
0119         f.write(self.getPycHeader())
0120         marshal.dump(self.code, f)
0121 
0122     MAGIC = imp.get_magic()
0123 
0124     def getPycHeader(self):
0125         # compile.c uses marshal to write a long directly, with
0126         # calling the interface that would also generate a 1-byte code
0127         # to indicate the type of the value.  simplest way to get the
0128         # same effect is to call marshal and then skip the code.
0129         mtime = os.path.getmtime(self.filename)
0130         mtime = struct.pack('<i', mtime)
0131         return self.MAGIC + mtime
0132 
0133 class LocalNameFinder:
0134     """Find local names in scope"""
0135     def __init__(self, names=()):
0136         self.names = misc.Set()
0137         self.globals = misc.Set()
0138         for name in names:
0139             self.names.add(name)
0140 
0141     # XXX list comprehensions and for loops
0142 
0143     def getLocals(self):
0144         for elt in self.globals.elements():
0145             if self.names.has_elt(elt):
0146                 self.names.remove(elt)
0147         return self.names
0148 
0149     def visitDict(self, node):
0150         pass
0151 
0152     def visitGlobal(self, node):
0153         for name in node.names:
0154             self.globals.add(name)
0155 
0156     def visitFunction(self, node):
0157         self.names.add(node.name)
0158 
0159     def visitLambda(self, node):
0160         pass
0161 
0162     def visitImport(self, node):
0163         for name, alias in node.names:
0164             self.names.add(alias or name)
0165 
0166     def visitFrom(self, node):
0167         for name, alias in node.names:
0168             self.names.add(alias or name)
0169 
0170     def visitClass(self, node):
0171         self.names.add(node.name)
0172 
0173     def visitAssName(self, node):
0174         self.names.add(node.name)
0175 
0176 def is_constant_false(node):
0177     if isinstance(node, ast.Const):
0178         if not node.value:
0179             return 1
0180     return 0
0181 
0182 class CodeGenerator:
0183     """Defines basic code generator for Python bytecode
0184 
0185     This class is an abstract base class.  Concrete subclasses must
0186     define an __init__() that defines self.graph and then calls the
0187     __init__() defined in this class.
0188 
0189     The concrete class must also define the class attributes
0190     NameFinder, FunctionGen, and ClassGen.  These attributes can be
0191     defined in the initClass() method, which is a hook for
0192     initializing these methods after all the classes have been
0193     defined.
0194     """
0195 
0196     optimized = 0 # is namespace access optimized?
0197     __initialized = None
0198     class_name = None # provide default for instance variable
0199 
0200     def __init__(self):
0201         if self.__initialized is None:
0202             self.initClass()
0203             self.__class__.__initialized = 1
0204         self.checkClass()
0205         self.locals = misc.Stack()
0206         self.setups = misc.Stack()
0207         self.last_lineno = None
0208         self._setupGraphDelegation()
0209         self._div_op = "BINARY_DIVIDE"
0210 
0211         # XXX set flags based on future features
0212         futures = self.get_module().futures
0213         for feature in futures:
0214             if feature == "division":
0215                 self.graph.setFlag(CO_FUTURE_DIVISION)
0216                 self._div_op = "BINARY_TRUE_DIVIDE"
0217             elif feature == "generators":
0218                 self.graph.setFlag(CO_GENERATOR_ALLOWED)
0219 
0220     def initClass(self):
0221         """This method is called once for each class"""
0222 
0223     def checkClass(self):
0224         """Verify that class is constructed correctly"""
0225         try:
0226             assert hasattr(self, 'graph')
0227             assert getattr(self, 'NameFinder')
0228             assert getattr(self, 'FunctionGen')
0229             assert getattr(self, 'ClassGen')
0230         except AssertionError, msg:
0231             intro = "Bad class construction for %s" % self.__class__.__name__
0232             raise AssertionError, intro
0233 
0234     def _setupGraphDelegation(self):
0235         self.emit = self.graph.emit
0236         self.newBlock = self.graph.newBlock
0237         self.startBlock = self.graph.startBlock
0238         self.nextBlock = self.graph.nextBlock
0239         self.setDocstring = self.graph.setDocstring
0240 
0241     def getCode(self):
0242         """Return a code object"""
0243         return self.graph.getCode()
0244 
0245     def mangle(self, name):
0246         if self.class_name is not None:
0247             return misc.mangle(name, self.class_name)
0248         else:
0249             return name
0250 
0251     def parseSymbols(self, tree):
0252         s = symbols.SymbolVisitor()
0253         walk(tree, s)
0254         return s.scopes
0255 
0256     def get_module(self):
0257         raise RuntimeError, "should be implemented by subclasses"
0258 
0259     # Next five methods handle name access
0260 
0261     def isLocalName(self, name):
0262         return self.locals.top().has_elt(name)
0263 
0264     def storeName(self, name):
0265         self._nameOp('STORE', name)
0266 
0267     def loadName(self, name):
0268         self._nameOp('LOAD', name)
0269 
0270     def delName(self, name):
0271         self._nameOp('DELETE', name)
0272 
0273     def _nameOp(self, prefix, name):
0274         name = self.mangle(name)
0275         scope = self.scope.check_name(name)
0276         if scope == SC_LOCAL:
0277             if not self.optimized:
0278                 self.emit(prefix + '_NAME', name)
0279             else:
0280                 self.emit(prefix + '_FAST', name)
0281         elif scope == SC_GLOBAL:
0282             if not self.optimized:
0283                 self.emit(prefix + '_NAME', name)
0284             else:
0285                 self.emit(prefix + '_GLOBAL', name)
0286         elif scope == SC_FREE or scope == SC_CELL:
0287             self.emit(prefix + '_DEREF', name)
0288         else:
0289             raise RuntimeError, "unsupported scope for var %s: %d" % \
0290                   (name, scope)
0291 
0292     def _implicitNameOp(self, prefix, name):
0293         """Emit name ops for names generated implicitly by for loops
0294 
0295         The interpreter generates names that start with a period or
0296         dollar sign.  The symbol table ignores these names because
0297         they aren't present in the program text.
0298         """
0299         if self.optimized:
0300             self.emit(prefix + '_FAST', name)
0301         else:
0302             self.emit(prefix + '_NAME', name)
0303 
0304     # The set_lineno() function and the explicit emit() calls for
0305     # SET_LINENO below are only used to generate the line number table.
0306     # As of Python 2.3, the interpreter does not have a SET_LINENO
0307     # instruction.  pyassem treats SET_LINENO opcodes as a special case.
0308 
0309     def set_lineno(self, node, force=False):
0310         """Emit SET_LINENO if necessary.
0311 
0312         The instruction is considered necessary if the node has a
0313         lineno attribute and it is different than the last lineno
0314         emitted.
0315 
0316         Returns true if SET_LINENO was emitted.
0317 
0318         There are no rules for when an AST node should have a lineno
0319         attribute.  The transformer and AST code need to be reviewed
0320         and a consistent policy implemented and documented.  Until
0321         then, this method works around missing line numbers.
0322         """
0323         lineno = getattr(node, 'lineno', None)
0324         if lineno is not None and (lineno != self.last_lineno
0325                                    or force):
0326             self.emit('SET_LINENO', lineno)
0327             self.last_lineno = lineno
0328             return True
0329         return False
0330 
0331     # The first few visitor methods handle nodes that generator new
0332     # code objects.  They use class attributes to determine what
0333     # specialized code generators to use.
0334 
0335     NameFinder = LocalNameFinder
0336     FunctionGen = None
0337     ClassGen = None
0338 
0339     def visitModule(self, node):
0340         self.scopes = self.parseSymbols(node)
0341         self.scope = self.scopes[node]
0342         self.emit('SET_LINENO', 0)
0343         if node.doc:
0344             self.emit('LOAD_CONST', node.doc)
0345             self.storeName('__doc__')
0346         lnf = walk(node.node, self.NameFinder(), verbose=0)
0347         self.locals.push(lnf.getLocals())
0348         self.visit(node.node)
0349         self.emit('LOAD_CONST', None)
0350         self.emit('RETURN_VALUE')
0351 
0352     def visitExpression(self, node):
0353         self.set_lineno(node)
0354         self.scopes = self.parseSymbols(node)
0355         self.scope = self.scopes[node]
0356         self.visit(node.node)
0357         self.emit('RETURN_VALUE')
0358 
0359     def visitFunction(self, node):
0360         self._visitFuncOrLambda(node, isLambda=0)
0361         if node.doc:
0362             self.setDocstring(node.doc)
0363         self.storeName(node.name)
0364 
0365     def visitLambda(self, node):
0366         self._visitFuncOrLambda(node, isLambda=1)
0367 
0368     def _visitFuncOrLambda(self, node, isLambda=0):
0369         if not isLambda and node.decorators:
0370             for decorator in node.decorators.nodes:
0371                 self.visit(decorator)
0372             ndecorators = len(node.decorators.nodes)
0373         else:
0374             ndecorators = 0
0375 
0376         gen = self.FunctionGen(node, self.scopes, isLambda,
0377                                self.class_name, self.get_module())
0378         walk(node.code, gen)
0379         gen.finish()
0380         self.set_lineno(node)
0381         for default in node.defaults:
0382             self.visit(default)
0383         frees = gen.scope.get_free_vars()
0384         if frees:
0385             for name in frees:
0386                 self.emit('LOAD_CLOSURE', name)
0387             self.emit('LOAD_CONST', gen)
0388             self.emit('MAKE_CLOSURE', len(node.defaults))
0389         else:
0390             self.emit('LOAD_CONST', gen)
0391             self.emit('MAKE_FUNCTION', len(node.defaults))
0392 
0393         for i in range(ndecorators):
0394             self.emit('CALL_FUNCTION', 1)
0395 
0396     def visitClass(self, node):
0397         gen = self.ClassGen(node, self.scopes,
0398                             self.get_module())
0399         walk(node.code, gen)
0400         gen.finish()
0401         self.set_lineno(node)
0402         self.emit('LOAD_CONST', node.name)
0403         for base in node.bases:
0404             self.visit(base)
0405         self.emit('BUILD_TUPLE', len(node.bases))
0406         frees = gen.scope.get_free_vars()
0407         for name in frees:
0408             self.emit('LOAD_CLOSURE', name)
0409         self.emit('LOAD_CONST', gen)
0410         if frees:
0411             self.emit('MAKE_CLOSURE', 0)
0412         else:
0413             self.emit('MAKE_FUNCTION', 0)
0414         self.emit('CALL_FUNCTION', 0)
0415         self.emit('BUILD_CLASS')
0416         self.storeName(node.name)
0417 
0418     # The rest are standard visitor methods
0419 
0420     # The next few implement control-flow statements
0421 
0422     def visitIf(self, node):
0423         end = self.newBlock()
0424         numtests = len(node.tests)
0425         for i in range(numtests):
0426             test, suite = node.tests[i]
0427             if is_constant_false(test):
0428                 # XXX will need to check generator stuff here
0429                 continue
0430             self.set_lineno(test)
0431             self.visit(test)
0432             nextTest = self.newBlock()
0433             self.emit('JUMP_IF_FALSE', nextTest)
0434             self.nextBlock()
0435             self.emit('POP_TOP')
0436             self.visit(suite)
0437             self.emit('JUMP_FORWARD', end)
0438             self.startBlock(nextTest)
0439             self.emit('POP_TOP')
0440         if node.else_:
0441             self.visit(node.else_)
0442         self.nextBlock(end)
0443 
0444     def visitWhile(self, node):
0445         self.set_lineno(node)
0446 
0447         loop = self.newBlock()
0448         else_ = self.newBlock()
0449 
0450         after = self.newBlock()
0451         self.emit('SETUP_LOOP', after)
0452 
0453         self.nextBlock(loop)
0454         self.setups.push((LOOP, loop))
0455 
0456         self.set_lineno(node, force=True)
0457         self.visit(node.test)
0458         self.emit('JUMP_IF_FALSE', else_ or after)
0459 
0460         self.nextBlock()
0461         self.emit('POP_TOP')
0462         self.visit(node.body)
0463         self.emit('JUMP_ABSOLUTE', loop)
0464 
0465         self.startBlock(else_) # or just the POPs if not else clause
0466         self.emit('POP_TOP')
0467         self.emit('POP_BLOCK')
0468         self.setups.pop()
0469         if node.else_:
0470             self.visit(node.else_)
0471         self.nextBlock(after)
0472 
0473     def visitFor(self, node):
0474         start = self.newBlock()
0475         anchor = self.newBlock()
0476         after = self.newBlock()
0477         self.setups.push((LOOP, start))
0478 
0479         self.set_lineno(node)
0480         self.emit('SETUP_LOOP', after)
0481         self.visit(node.list)
0482         self.emit('GET_ITER')
0483 
0484         self.nextBlock(start)
0485         self.set_lineno(node, force=1)
0486         self.emit('FOR_ITER', anchor)
0487         self.visit(node.assign)
0488         self.visit(node.body)
0489         self.emit('JUMP_ABSOLUTE', start)
0490         self.nextBlock(anchor)
0491         self.emit('POP_BLOCK')
0492         self.setups.pop()
0493         if node.else_:
0494             self.visit(node.else_)
0495         self.nextBlock(after)
0496 
0497     def visitBreak(self, node):
0498         if not self.setups:
0499             raise SyntaxError, "'break' outside loop (%s, %d)" % \
0500                   (node.filename, node.lineno)
0501         self.set_lineno(node)
0502         self.emit('BREAK_LOOP')
0503 
0504     def visitContinue(self, node):
0505         if not self.setups:
0506             raise SyntaxError, "'continue' outside loop (%s, %d)" % \
0507                   (node.filename, node.lineno)
0508         kind, block = self.setups.top()
0509         if kind == LOOP:
0510             self.set_lineno(node)
0511             self.emit('JUMP_ABSOLUTE', block)
0512             self.nextBlock()
0513         elif kind == EXCEPT or kind == TRY_FINALLY:
0514             self.set_lineno(node)
0515             # find the block that starts the loop
0516             top = len(self.setups)
0517             while top > 0:
0518                 top = top - 1
0519                 kind, loop_block = self.setups[top]
0520                 if kind == LOOP:
0521                     break
0522             if kind != LOOP:
0523                 raise SyntaxError, "'continue' outside loop (%s, %d)" % \
0524                       (node.filename, node.lineno)
0525             self.emit('CONTINUE_LOOP', loop_block)
0526             self.nextBlock()
0527         elif kind == END_FINALLY:
0528             msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
0529             raise SyntaxError, msg % (node.filename, node.lineno)
0530 
0531     def visitTest(self, node, jump):
0532         end = self.newBlock()
0533         for child in node.nodes[:-1]:
0534             self.visit(child)
0535             self.emit(jump, end)
0536             self.nextBlock()
0537             self.emit('POP_TOP')
0538         self.visit(node.nodes[-1])
0539         self.nextBlock(end)
0540 
0541     def visitAnd(self, node):
0542         self.visitTest(node, 'JUMP_IF_FALSE')
0543 
0544     def visitOr(self, node):
0545         self.visitTest(node, 'JUMP_IF_TRUE')
0546 
0547     def visitCompare(self, node):
0548         self.visit(node.expr)
0549         cleanup = self.newBlock()
0550         for op, code in node.ops[:-1]:
0551             self.visit(code)
0552             self.emit('DUP_TOP')
0553             self.emit('ROT_THREE')
0554             self.emit('COMPARE_OP', op)
0555             self.emit('JUMP_IF_FALSE', cleanup)
0556             self.nextBlock()
0557             self.emit('POP_TOP')
0558         # now do the last comparison
0559         if node.ops:
0560             op, code = node.ops[-1]
0561             self.visit(code)
0562             self.emit('COMPARE_OP', op)
0563         if len(node.ops) > 1:
0564             end = self.newBlock()
0565             self.emit('JUMP_FORWARD', end)
0566             self.startBlock(cleanup)
0567             self.emit('ROT_TWO')
0568             self.emit('POP_TOP')
0569             self.nextBlock(end)
0570 
0571     # list comprehensions
0572     __list_count = 0
0573 
0574     def visitListComp(self, node):
0575         self.set_lineno(node)
0576         # setup list
0577         append = "$append%d" % self.__list_count
0578         self.__list_count = self.__list_count + 1
0579         self.emit('BUILD_LIST', 0)
0580         self.emit('DUP_TOP')
0581         self.emit('LOAD_ATTR', 'append')
0582         self._implicitNameOp('STORE', append)
0583 
0584         stack = []
0585         for i, for_ in zip(range(len(node.quals)), node.quals):
0586             start, anchor = self.visit(for_)
0587             cont = None
0588             for if_ in for_.ifs:
0589                 if cont is None:
0590                     cont = self.newBlock()
0591                 self.visit(if_, cont)
0592             stack.insert(0, (start, cont, anchor))
0593 
0594         self._implicitNameOp('LOAD', append)
0595         self.visit(node.expr)
0596         self.emit('CALL_FUNCTION', 1)
0597         self.emit('POP_TOP')
0598 
0599         for start, cont, anchor in stack:
0600             if cont:
0601                 skip_one = self.newBlock()
0602                 self.emit('JUMP_FORWARD', skip_one)
0603                 self.startBlock(cont)
0604                 self.emit('POP_TOP')
0605                 self.nextBlock(skip_one)
0606             self.emit('JUMP_ABSOLUTE', start)
0607             self.startBlock(anchor)
0608         self._implicitNameOp('DELETE', append)
0609 
0610         self.__list_count = self.__list_count - 1
0611 
0612     def visitListCompFor(self, node):
0613         start = self.newBlock()
0614         anchor = self.newBlock()
0615 
0616         self.visit(node.list)
0617         self.emit('GET_ITER')
0618         self.nextBlock(start)
0619         self.set_lineno(node, force=True)
0620         self.emit('FOR_ITER', anchor)
0621         self.nextBlock()
0622         self.visit(node.assign)
0623         return start, anchor
0624 
0625     def visitListCompIf(self, node, branch):
0626         self.set_lineno(node, force=True)
0627         self.visit(node.test)
0628         self.emit('JUMP_IF_FALSE', branch)
0629         self.newBlock()
0630         self.emit('POP_TOP')
0631 
0632     def visitGenExpr(self, node):
0633         gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
0634                                    self.get_module())
0635         walk(node.code, gen)
0636         gen.finish()
0637         self.set_lineno(node)
0638         frees = gen.scope.get_free_vars()
0639         if frees:
0640             for name in frees:
0641                 self.emit('LOAD_CLOSURE', name)
0642             self.emit('LOAD_CONST', gen)
0643             self.emit('MAKE_CLOSURE', 0)
0644         else:
0645             self.emit('LOAD_CONST', gen)
0646             self.emit('MAKE_FUNCTION', 0)
0647 
0648         # precomputation of outmost iterable
0649         self.visit(node.code.quals[0].iter)
0650         self.emit('GET_ITER')
0651         self.emit('CALL_FUNCTION', 1)
0652 
0653     def visitGenExprInner(self, node):
0654         self.set_lineno(node)
0655         # setup list
0656 
0657         stack = []
0658         for i, for_ in zip(range(len(node.quals)), node.quals):
0659             start, anchor = self.visit(for_)
0660             cont = None
0661             for if_ in for_.ifs:
0662                 if cont is None:
0663                     cont = self.newBlock()
0664                 self.visit(if_, cont)
0665             stack.insert(0, (start, cont, anchor))
0666 
0667         self.visit(node.expr)
0668         self.emit('YIELD_VALUE')
0669 
0670         for start, cont, anchor in stack:
0671             if cont:
0672                 skip_one = self.newBlock()
0673                 self.emit('JUMP_FORWARD', skip_one)
0674                 self.startBlock(cont)
0675                 self.emit('POP_TOP')
0676                 self.nextBlock(skip_one)
0677             self.emit('JUMP_ABSOLUTE', start)
0678             self.startBlock(anchor)
0679         self.emit('LOAD_CONST', None)
0680 
0681     def visitGenExprFor(self, node):
0682         start = self.newBlock()
0683         anchor = self.newBlock()
0684 
0685         if node.is_outmost:
0686             self.loadName('[outmost-iterable]')
0687         else:
0688             self.visit(node.iter)
0689             self.emit('GET_ITER')
0690 
0691         self.nextBlock(start)
0692         self.set_lineno(node, force=True)
0693         self.emit('FOR_ITER', anchor)
0694         self.nextBlock()
0695         self.visit(node.assign)
0696         return start, anchor
0697 
0698     def visitGenExprIf(self, node, branch):
0699         self.set_lineno(node, force=True)
0700         self.visit(node.test)
0701         self.emit('JUMP_IF_FALSE', branch)
0702         self.newBlock()
0703         self.emit('POP_TOP')
0704 
0705     # exception related
0706 
0707     def visitAssert(self, node):
0708         # XXX would be interesting to implement this via a
0709         # transformation of the AST before this stage
0710         if __debug__:
0711             end = self.newBlock()
0712             self.set_lineno(node)
0713             # XXX AssertionError appears to be special case -- it is always
0714             # loaded as a global even if there is a local name.  I guess this
0715             # is a sort of renaming op.
0716             self.nextBlock()
0717             self.visit(node.test)
0718             self.emit('JUMP_IF_TRUE', end)
0719             self.nextBlock()
0720             self.emit('POP_TOP')
0721             self.emit('LOAD_GLOBAL', 'AssertionError')
0722             if node.fail:
0723                 self.visit(node.fail)
0724                 self.emit('RAISE_VARARGS', 2)
0725             else:
0726                 self.emit('RAISE_VARARGS', 1)
0727             self.nextBlock(end)
0728             self.emit('POP_TOP')
0729 
0730     def visitRaise(self, node):
0731         self.set_lineno(node)
0732         n = 0
0733         if node.expr1:
0734             self.visit(node.expr1)
0735             n = n + 1
0736         if node.expr2:
0737             self.visit(node.expr2)
0738             n = n + 1
0739         if node.expr3:
0740             self.visit(node.expr3)
0741             n = n + 1
0742         self.emit('RAISE_VARARGS', n)
0743 
0744     def visitTryExcept(self, node):
0745         body = self.newBlock()
0746         handlers = self.newBlock()
0747         end = self.newBlock()
0748         if node.else_:
0749             lElse = self.newBlock()
0750         else:
0751             lElse = end
0752         self.set_lineno(node)
0753         self.emit('SETUP_EXCEPT', handlers)
0754         self.nextBlock(body)
0755         self.setups.push((EXCEPT, body))
0756         self.visit(node.body)
0757         self.emit('POP_BLOCK')
0758         self.setups.pop()
0759         self.emit('JUMP_FORWARD', lElse)
0760         self.startBlock(handlers)
0761 
0762         last = len(node.handlers) - 1
0763         for i in range(len(node.handlers)):
0764             expr, target, body = node.handlers[i]
0765             self.set_lineno(expr)
0766             if expr:
0767                 self.emit('DUP_TOP')
0768                 self.visit(expr)
0769                 self.emit('COMPARE_OP', 'exception match')
0770                 next = self.newBlock()
0771                 self.emit('JUMP_IF_FALSE', next)
0772                 self.nextBlock()
0773                 self.emit('POP_TOP')
0774             self.emit('POP_TOP')
0775             if target:
0776                 self.visit(target)
0777             else:
0778                 self.emit('POP_TOP')
0779             self.emit('POP_TOP')
0780             self.visit(body)
0781             self.emit('JUMP_FORWARD', end)
0782             if expr:
0783                 self.nextBlock(next)
0784             else:
0785                 self.nextBlock()
0786             if expr: # XXX
0787                 self.emit('POP_TOP')
0788         self.emit('END_FINALLY')
0789         if node.else_:
0790             self.nextBlock(lElse)
0791             self.visit(node.else_)
0792         self.nextBlock(end)
0793 
0794     def visitTryFinally(self, node):
0795         body = self.newBlock()
0796         final = self.newBlock()
0797         self.set_lineno(node)
0798         self.emit('SETUP_FINALLY', final)
0799         self.nextBlock(body)
0800         self.setups.push((TRY_FINALLY, body))
0801         self.visit(node.body)
0802         self.emit('POP_BLOCK')
0803         self.setups.pop()
0804         self.emit('LOAD_CONST', None)
0805         self.nextBlock(final)
0806         self.setups.push((END_FINALLY, final))
0807         self.visit(node.final)
0808         self.emit('END_FINALLY')
0809         self.setups.pop()
0810 
0811     # misc
0812 
0813     def visitDiscard(self, node):
0814         self.set_lineno(node)
0815         self.visit(node.expr)
0816         self.emit('POP_TOP')
0817 
0818     def visitConst(self, node):
0819         self.emit('LOAD_CONST', node.value)
0820 
0821     def visitKeyword(self, node):
0822         self.emit('LOAD_CONST', node.name)
0823         self.visit(node.expr)
0824 
0825     def visitGlobal(self, node):
0826         # no code to generate
0827         pass
0828 
0829     def visitName(self, node):
0830         self.set_lineno(node)
0831         self.loadName(node.name)
0832 
0833     def visitPass(self, node):
0834         self.set_lineno(node)
0835 
0836     def visitImport(self, node):
0837         self.set_lineno(node)
0838         for name, alias in node.names:
0839             if VERSION > 1:
0840                 self.emit('LOAD_CONST', None)
0841             self.emit('IMPORT_NAME', name)
0842             mod = name.split(".")[0]
0843             if alias:
0844                 self._resolveDots(name)
0845                 self.storeName(alias)
0846             else:
0847                 self.storeName(mod)
0848 
0849     def visitFrom(self, node):
0850         self.set_lineno(node)
0851         fromlist = map(lambda (name, alias): name, node.names)
0852         if VERSION > 1:
0853             self.emit('LOAD_CONST', tuple(fromlist))
0854         self.emit('IMPORT_NAME', node.modname)
0855         for name, alias in node.names:
0856             if VERSION > 1:
0857                 if name == '*':
0858                     self.namespace = 0
0859                     self.emit('IMPORT_STAR')
0860                     # There can only be one name w/ from ... import *
0861                     assert len(node.names) == 1
0862                     return
0863                 else:
0864                     self.emit('IMPORT_FROM', name)
0865                     self._resolveDots(name)
0866                     self.storeName(alias or name)
0867             else:
0868                 self.emit('IMPORT_FROM', name)
0869         self.emit('POP_TOP')
0870 
0871     def _resolveDots(self, name):
0872         elts = name.split(".")
0873         if len(elts) == 1:
0874             return
0875         for elt in elts[1:]:
0876             self.emit('LOAD_ATTR', elt)
0877 
0878     def visitGetattr(self, node):
0879         self.visit(node.expr)
0880         self.emit('LOAD_ATTR', self.mangle(node.attrname))
0881 
0882     # next five implement assignments
0883 
0884     def visitAssign(self, node):
0885         self.set_lineno(node)
0886         self.visit(node.expr)
0887         dups = len(node.nodes) - 1
0888         for i in range(len(node.nodes)):
0889             elt = node.nodes[i]
0890             if i < dups:
0891                 self.emit('DUP_TOP')
0892             if isinstance(elt, ast.Node):
0893                 self.visit(elt)
0894 
0895     def visitAssName(self, node):
0896         if node.flags == 'OP_ASSIGN':
0897             self.storeName(node.name)
0898         elif node.flags == 'OP_DELETE':
0899             self.set_lineno(node)
0900             self.delName(node.name)
0901         else:
0902             print "oops", node.flags
0903 
0904     def visitAssAttr(self, node):
0905         self.visit(node.expr)
0906         if node.flags == 'OP_ASSIGN':
0907             self.emit('STORE_ATTR', self.mangle(node.attrname))
0908         elif node.flags == 'OP_DELETE':
0909             self.emit('DELETE_ATTR', self.mangle(node.attrname))
0910         else:
0911             print "warning: unexpected flags:", node.flags
0912             print node
0913 
0914     def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
0915         if findOp(node) != 'OP_DELETE':
0916             self.emit(op, len(node.nodes))
0917         for child in node.nodes:
0918             self.visit(child)
0919 
0920     if VERSION > 1:
0921         visitAssTuple = _visitAssSequence
0922         visitAssList = _visitAssSequence
0923     else:
0924         def visitAssTuple(self, node):
0925             self._visitAssSequence(node, 'UNPACK_TUPLE')
0926 
0927         def visitAssList(self, node):
0928             self._visitAssSequence(node, 'UNPACK_LIST')
0929 
0930     # augmented assignment
0931 
0932     def visitAugAssign(self, node):
0933         self.set_lineno(node)
0934         aug_node = wrap_aug(node.node)
0935         self.visit(aug_node, "load")
0936         self.visit(node.expr)
0937         self.emit(self._augmented_opcode[node.op])
0938         self.visit(aug_node, "store")
0939 
0940     _augmented_opcode = {
0941         '+=' : 'INPLACE_ADD',
0942         '-=' : 'INPLACE_SUBTRACT',
0943         '*=' : 'INPLACE_MULTIPLY',
0944         '/=' : 'INPLACE_DIVIDE',
0945         '//=': 'INPLACE_FLOOR_DIVIDE',
0946         '%=' : 'INPLACE_MODULO',
0947         '**=': 'INPLACE_POWER',
0948         '>>=': 'INPLACE_RSHIFT',
0949         '<<=': 'INPLACE_LSHIFT',
0950         '&=' : 'INPLACE_AND',
0951         '^=' : 'INPLACE_XOR',
0952         '|=' : 'INPLACE_OR',
0953         }
0954 
0955     def visitAugName(self, node, mode):
0956         if mode == "load":
0957             self.loadName(node.name)
0958         elif mode == "store":
0959             self.storeName(node.name)
0960 
0961     def visitAugGetattr(self, node, mode):
0962         if mode == "load":
0963             self.visit(node.expr)
0964             self.emit('DUP_TOP')
0965             self.emit('LOAD_ATTR', self.mangle(node.attrname))
0966         elif mode == "store":
0967             self.emit('ROT_TWO')
0968             self.emit('STORE_ATTR', self.mangle(node.attrname))
0969 
0970     def visitAugSlice(self, node, mode):
0971         if mode == "load":
0972             self.visitSlice(node, 1)
0973         elif mode == "store":
0974             slice = 0
0975             if node.lower:
0976                 slice = slice | 1
0977             if node.upper:
0978                 slice = slice | 2
0979             if slice == 0:
0980                 self.emit('ROT_TWO')
0981             elif slice == 3:
0982                 self.emit('ROT_FOUR')
0983             else:
0984                 self.emit('ROT_THREE')
0985             self.emit('STORE_SLICE+%d' % slice)
0986 
0987     def visitAugSubscript(self, node, mode):
0988         if len(node.subs) > 1:
0989             raise SyntaxError, "augmented assignment to tuple is not possible"
0990         if mode == "load":
0991             self.visitSubscript(node, 1)
0992         elif mode == "store":
0993             self.emit('ROT_THREE')
0994             self.emit('STORE_SUBSCR')
0995 
0996     def visitExec(self, node):
0997         self.visit(node.expr)
0998         if node.locals is None:
0999             self.emit('LOAD_CONST', None)
1000         else:
1001             self.visit(node.locals)
1002         if node.globals is None:
1003             self.emit('DUP_TOP')
1004         else:
1005             self.visit(node.globals)
1006         self.emit('EXEC_STMT')
1007 
1008     def visitCallFunc(self, node):
1009         pos = 0
1010         kw = 0
1011         self.set_lineno(node)
1012         self.visit(node.node)
1013         for arg in node.args:
1014             self.visit(arg)
1015             if isinstance(arg, ast.Keyword):
1016                 kw = kw + 1
1017             else:
1018                 pos = pos + 1
1019         if node.star_args is not None:
1020             self.visit(node.star_args)
1021         if node.dstar_args is not None:
1022             self.visit(node.dstar_args)
1023         have_star = node.star_args is not None
1024         have_dstar = node.dstar_args is not None
1025         opcode = callfunc_opcode_info[have_star, have_dstar]
1026         self.emit(opcode, kw << 8 | pos)
1027 
1028     def visitPrint(self, node, newline=0):
1029         self.set_lineno(node)
1030         if node.dest:
1031             self.visit(node.dest)
1032         for child in node.nodes:
1033             if node.dest:
1034                 self.emit('DUP_TOP')
1035             self.visit(child)
1036             if node.dest:
1037                 self.emit('ROT_TWO')
1038                 self.emit('PRINT_ITEM_TO')
1039             else:
1040                 self.emit('PRINT_ITEM')
1041         if node.dest and not newline:
1042             self.emit('POP_TOP')
1043 
1044     def visitPrintnl(self, node):
1045         self.visitPrint(node, newline=1)
1046         if node.dest:
1047             self.emit('PRINT_NEWLINE_TO')
1048         else:
1049             self.emit('PRINT_NEWLINE')
1050 
1051     def visitReturn(self, node):
1052         self.set_lineno(node)
1053         self.visit(node.value)
1054         self.emit('RETURN_VALUE')
1055 
1056     def visitYield(self, node):
1057         self.set_lineno(node)
1058         self.visit(node.value)
1059         self.emit('YIELD_VALUE')
1060 
1061     # slice and subscript stuff
1062 
1063     def visitSlice(self, node, aug_flag=None):
1064         # aug_flag is used by visitAugSlice
1065         self.visit(node.expr)
1066         slice = 0
1067         if node.lower:
1068             self.visit(node.lower)
1069             slice = slice | 1
1070         if node.upper:
1071             self.visit(node.upper)
1072             slice = slice | 2
1073         if aug_flag:
1074             if slice == 0:
1075                 self.emit('DUP_TOP')
1076             elif slice == 3:
1077                 self.emit('DUP_TOPX', 3)
1078             else:
1079                 self.emit('DUP_TOPX', 2)
1080         if node.flags == 'OP_APPLY':
1081             self.emit('SLICE+%d' % slice)
1082         elif node.flags == 'OP_ASSIGN':
1083             self.emit('STORE_SLICE+%d' % slice)
1084         elif node.flags == 'OP_DELETE':
1085             self.emit('DELETE_SLICE+%d' % slice)
1086         else:
1087             print "weird slice", node.flags
1088             raise
1089 
1090     def visitSubscript(self, node, aug_flag=None):
1091         self.visit(node.expr)
1092         for sub in node.subs:
1093             self.visit(sub)
1094         if aug_flag:
1095             self.emit('DUP_TOPX', 2)
1096         if len(node.subs) > 1:
1097             self.emit('BUILD_TUPLE', len(node.subs))
1098         if node.flags == 'OP_APPLY':
1099             self.emit('BINARY_SUBSCR')
1100         elif node.flags == 'OP_ASSIGN':
1101             self.emit('STORE_SUBSCR')
1102         elif node.flags == 'OP_DELETE':
1103             self.emit('DELETE_SUBSCR')
1104 
1105     # binary ops
1106 
1107     def binaryOp(self, node, op):
1108         self.visit(node.left)
1109         self.visit(node.right)
1110         self.emit(op)
1111 
1112     def visitAdd(self, node):
1113         return self.binaryOp(node, 'BINARY_ADD')
1114 
1115     def visitSub(self, node):
1116         return self.binaryOp(node, 'BINARY_SUBTRACT')
1117 
1118     def visitMul(self, node):
1119         return self.binaryOp(node, 'BINARY_MULTIPLY')
1120 
1121     def visitDiv(self, node):
1122         return self.binaryOp(node, self._div_op)
1123 
1124     def visitFloorDiv(self, node):
1125         return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
1126 
1127     def visitMod(self, node):
1128         return self.binaryOp(node, 'BINARY_MODULO')
1129 
1130     def visitPower(self, node):
1131         return self.binaryOp(node, 'BINARY_POWER')
1132 
1133     def visitLeftShift(self, node):
1134         return self.binaryOp(node, 'BINARY_LSHIFT')
1135 
1136     def visitRightShift(self, node):
1137         return self.binaryOp(node, 'BINARY_RSHIFT')
1138 
1139     # unary ops
1140 
1141     def unaryOp(self, node, op):
1142         self.visit(node.expr)
1143         self.emit(op)
1144 
1145     def visitInvert(self, node):
1146         return self.unaryOp(node, 'UNARY_INVERT')
1147 
1148     def visitUnarySub(self, node):
1149         return self.unaryOp(node, 'UNARY_NEGATIVE')
1150 
1151     def visitUnaryAdd(self, node):
1152         return self.unaryOp(node, 'UNARY_POSITIVE')
1153 
1154     def visitUnaryInvert(self, node):
1155         return self.unaryOp(node, 'UNARY_INVERT')
1156 
1157     def visitNot(self, node):
1158         return self.unaryOp(node, 'UNARY_NOT')
1159 
1160     def visitBackquote(self, node):
1161         return self.unaryOp(node, 'UNARY_CONVERT')
1162 
1163     # bit ops
1164 
1165     def bitOp(self, nodes, op):
1166         self.visit(nodes[0])
1167         for node in nodes[1:]:
1168             self.visit(node)
1169             self.emit(op)
1170 
1171     def visitBitand(self, node):
1172         return self.bitOp(node.nodes, 'BINARY_AND')
1173 
1174     def visitBitor(self, node):
1175         return self.bitOp(node.nodes, 'BINARY_OR')
1176 
1177     def visitBitxor(self, node):
1178         return self.bitOp(node.nodes, 'BINARY_XOR')
1179 
1180     # object constructors
1181 
1182     def visitEllipsis(self, node):
1183         self.emit('LOAD_CONST', Ellipsis)
1184 
1185     def visitTuple(self, node):
1186         self.set_lineno(node)
1187         for elt in node.nodes:
1188             self.visit(elt)
1189         self.emit('BUILD_TUPLE', len(node.nodes))
1190 
1191     def visitList(self, node):
1192         self.set_lineno(node)
1193         for elt in node.nodes:
1194             self.visit(elt)
1195         self.emit('BUILD_LIST', len(node.nodes))
1196 
1197     def visitSliceobj(self, node):
1198         for child in node.nodes:
1199             self.visit(child)
1200         self.emit('BUILD_SLICE', len(node.nodes))
1201 
1202     def visitDict(self, node):
1203         self.set_lineno(node)
1204         self.emit('BUILD_MAP', 0)
1205         for k, v in node.items:
1206             self.emit('DUP_TOP')
1207             self.visit(k)
1208             self.visit(v)
1209             self.emit('ROT_THREE')
1210             self.emit('STORE_SUBSCR')
1211 
1212 class NestedScopeMixin:
1213     """Defines initClass() for nested scoping (Python 2.2-compatible)"""
1214     def initClass(self):
1215         self.__class__.NameFinder = LocalNameFinder
1216         self.__class__.FunctionGen = FunctionCodeGenerator
1217         self.__class__.ClassGen = ClassCodeGenerator
1218 
1219 class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
1220     __super_init = CodeGenerator.__init__
1221 
1222     scopes = None
1223 
1224     def __init__(self, tree):
1225         self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
1226         self.futures = future.find_futures(tree)
1227         self.__super_init()
1228         walk(tree, self)
1229 
1230     def get_module(self):
1231         return self
1232 
1233 class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
1234     __super_init = CodeGenerator.__init__
1235 
1236     scopes = None
1237     futures = ()
1238 
1239     def __init__(self, tree):
1240         self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
1241         self.__super_init()
1242         walk(tree, self)
1243 
1244     def get_module(self):
1245         return self
1246 
1247 class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
1248 
1249     __super_init = CodeGenerator.__init__
1250 
1251     scopes = None
1252     futures = ()
1253 
1254     def __init__(self, tree):
1255         self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
1256         self.__super_init()
1257         self.set_lineno(tree)
1258         walk(tree, self)
1259         self.emit('RETURN_VALUE')
1260 
1261     def get_module(self):
1262         return self
1263 
1264     def visitDiscard(self, node):
1265         # XXX Discard means it's an expression.  Perhaps this is a bad
1266         # name.
1267         self.visit(node.expr)
1268         self.emit('PRINT_EXPR')
1269 
1270 class AbstractFunctionCode:
1271     optimized = 1
1272     lambdaCount = 0
1273 
1274     def __init__(self, func, scopes, isLambda, class_name, mod):
1275         self.class_name = class_name
1276         self.module = mod
1277         if isLambda:
1278             klass = FunctionCodeGenerator
1279             name = "<lambda.%d>" % klass.lambdaCount
1280             klass.lambdaCount = klass.lambdaCount + 1
1281         else:
1282             name = func.name
1283 
1284         args, hasTupleArg = generateArgList(func.argnames)
1285         self.graph = pyassem.PyFlowGraph(name, func.filename, args,
1286                                          optimized=1)
1287         self.isLambda = isLambda
1288         self.super_init()
1289 
1290         if not isLambda and func.doc:
1291             self.setDocstring(func.doc)
1292 
1293         lnf = walk(func.code, self.NameFinder(args), verbose=0)
1294         self.locals.push(lnf.getLocals())
1295         if func.varargs:
1296             self.graph.setFlag(CO_VARARGS)
1297         if func.kwargs:
1298             self.graph.setFlag(CO_VARKEYWORDS)
1299         self.set_lineno(func)
1300         if hasTupleArg:
1301             self.generateArgUnpack(func.argnames)
1302 
1303     def get_module(self):
1304         return self.module
1305 
1306     def finish(self):
1307         self.graph.startExitBlock()
1308         if not self.isLambda:
1309             self.emit('LOAD_CONST', None)
1310         self.emit('RETURN_VALUE')
1311 
1312     def generateArgUnpack(self, args):
1313         for i in range(len(args)):
1314             arg = args[i]
1315             if type(arg) == types.TupleType:
1316                 self.emit('LOAD_FAST', '.%d' % (i * 2))
1317                 self.unpackSequence(arg)
1318 
1319     def unpackSequence(self, tup):
1320         if VERSION > 1:
1321             self.emit('UNPACK_SEQUENCE', len(tup))
1322         else:
1323             self.emit('UNPACK_TUPLE', len(tup))
1324         for elt in tup:
1325             if type(elt) == types.TupleType:
1326                 self.unpackSequence(elt)
1327             else:
1328                 self._nameOp('STORE', elt)
1329 
1330     unpackTuple = unpackSequence
1331 
1332 class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1333                             CodeGenerator):
1334     super_init = CodeGenerator.__init__ # call be other init
1335     scopes = None
1336 
1337     __super_init = AbstractFunctionCode.__init__
1338 
1339     def __init__(self, func, scopes, isLambda, class_name, mod):
1340         self.scopes = scopes
1341         self.scope = scopes[func]
1342         self.__super_init(func, scopes, isLambda, class_name, mod)
1343         self.graph.setFreeVars(self.scope.get_free_vars())
1344         self.graph.setCellVars(self.scope.get_cell_vars())
1345         if self.scope.generator is not None:
1346             self.graph.setFlag(CO_GENERATOR)
1347 
1348 class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
1349                            CodeGenerator):
1350     super_init = CodeGenerator.__init__ # call be other init
1351     scopes = None
1352 
1353     __super_init = AbstractFunctionCode.__init__
1354 
1355     def __init__(self, gexp, scopes, class_name, mod):
1356         self.scopes = scopes
1357         self.scope = scopes[gexp]
1358         self.__super_init(gexp, scopes, 1, class_name, mod)
1359         self.graph.setFreeVars(self.scope.get_free_vars())
1360         self.graph.setCellVars(self.scope.get_cell_vars())
1361         self.graph.setFlag(CO_GENERATOR)
1362 
1363 class AbstractClassCode:
1364 
1365     def __init__(self, klass, scopes, module):
1366         self.class_name = klass.name
1367         self.module = module
1368         self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
1369                                            optimized=0, klass=1)
1370         self.super_init()
1371         lnf = walk(klass.code, self.NameFinder(), verbose=0)
1372         self.locals.push(lnf.getLocals())
1373         self.graph.setFlag(CO_NEWLOCALS)
1374         if klass.doc:
1375             self.setDocstring(klass.doc)
1376 
1377     def get_module(self):
1378         return self.module
1379 
1380     def finish(self):
1381         self.graph.startExitBlock()
1382         self.emit('LOAD_LOCALS')
1383         self.emit('RETURN_VALUE')
1384 
1385 class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
1386     super_init = CodeGenerator.__init__
1387     scopes = None
1388 
1389     __super_init = AbstractClassCode.__init__
1390 
1391     def __init__(self, klass, scopes, module):
1392         self.scopes = scopes
1393         self.scope = scopes[klass]
1394         self.__super_init(klass, scopes, module)
1395         self.graph.setFreeVars(self.scope.get_free_vars())
1396         self.graph.setCellVars(self.scope.get_cell_vars())
1397         self.set_lineno(klass)
1398         self.emit("LOAD_GLOBAL", "__name__")
1399         self.storeName("__module__")
1400         if klass.doc:
1401             self.emit("LOAD_CONST", klass.doc)
1402             self.storeName('__doc__')
1403 
1404 def generateArgList(arglist):
1405     """Generate an arg list marking TupleArgs"""
1406     args = []
1407     extra = []
1408     count = 0
1409     for i in range(len(arglist)):
1410         elt = arglist[i]
1411         if type(elt) == types.StringType:
1412             args.append(elt)
1413         elif type(elt) == types.TupleType:
1414             args.append(TupleArg(i * 2, elt))
1415             extra.extend(misc.flatten(elt))
1416             count = count + 1
1417         else:
1418             raise ValueError, "unexpect argument type:", elt
1419     return args + extra, count
1420 
1421 def findOp(node):
1422     """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
1423     v = OpFinder()
1424     walk(node, v, verbose=0)
1425     return v.op
1426 
1427 class OpFinder:
1428     def __init__(self):
1429         self.op = None
1430     def visitAssName(self, node):
1431         if self.op is None:
1432             self.op = node.flags
1433         elif self.op != node.flags:
1434             raise ValueError, "mixed ops in stmt"
1435     visitAssAttr = visitAssName
1436     visitSubscript = visitAssName
1437 
1438 class Delegator:
1439     """Base class to support delegation for augmented assignment nodes
1440 
1441     To generator code for augmented assignments, we use the following
1442     wrapper classes.  In visitAugAssign, the left-hand expression node
1443     is visited twice.  The first time the visit uses the normal method
1444     for that node .  The second time the visit uses a different method
1445     that generates the appropriate code to perform the assignment.
1446     These delegator classes wrap the original AST nodes in order to
1447     support the variant visit methods.
1448     """
1449     def __init__(self, obj):
1450         self.obj = obj
1451 
1452     def __getattr__(self, attr):
1453         return getattr(self.obj, attr)
1454 
1455 class AugGetattr(Delegator):
1456     pass
1457 
1458 class AugName(Delegator):
1459     pass
1460 
1461 class AugSlice(Delegator):
1462     pass
1463 
1464 class AugSubscript(Delegator):
1465     pass
1466 
1467 wrapper = {
1468     ast.Getattr: AugGetattr,
1469     ast.Name: AugName,
1470     ast.Slice: AugSlice,
1471     ast.Subscript: AugSubscript,
1472     }
1473 
1474 def wrap_aug(node):
1475     return wrapper[node.__class__](node)
1476 
1477 if __name__ == "__main__":
1478     for file in sys.argv[1:]:
1479         compileFile(file)
1480 

Generated by PyXR 0.9.4
SourceForge.net Logo