PageRenderTime 1324ms CodeModel.GetById 222ms app.highlight 931ms RepoModel.GetById 155ms app.codeStats 1ms

/Lib/compiler/pycodegen.py

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