python-2.5.2/win32/Lib/compiler/pycodegen.py
changeset 0 ae805ac0140d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python-2.5.2/win32/Lib/compiler/pycodegen.py	Fri Apr 03 17:19:34 2009 +0100
@@ -0,0 +1,1533 @@
+import imp
+import os
+import marshal
+import struct
+import sys
+from cStringIO import StringIO
+
+from compiler import ast, parse, walk, syntax
+from compiler import pyassem, misc, future, symbols
+from compiler.consts import SC_LOCAL, SC_GLOBAL, SC_FREE, SC_CELL
+from compiler.consts import (CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS,
+     CO_NESTED, CO_GENERATOR, CO_FUTURE_DIVISION,
+     CO_FUTURE_ABSIMPORT, CO_FUTURE_WITH_STATEMENT)
+from compiler.pyassem import TupleArg
+
+# XXX The version-specific code can go, since this code only works with 2.x.
+# Do we have Python 1.x or Python 2.x?
+try:
+    VERSION = sys.version_info[0]
+except AttributeError:
+    VERSION = 1
+
+callfunc_opcode_info = {
+    # (Have *args, Have **args) : opcode
+    (0,0) : "CALL_FUNCTION",
+    (1,0) : "CALL_FUNCTION_VAR",
+    (0,1) : "CALL_FUNCTION_KW",
+    (1,1) : "CALL_FUNCTION_VAR_KW",
+}
+
+LOOP = 1
+EXCEPT = 2
+TRY_FINALLY = 3
+END_FINALLY = 4
+
+def compileFile(filename, display=0):
+    f = open(filename, 'U')
+    buf = f.read()
+    f.close()
+    mod = Module(buf, filename)
+    try:
+        mod.compile(display)
+    except SyntaxError:
+        raise
+    else:
+        f = open(filename + "c", "wb")
+        mod.dump(f)
+        f.close()
+
+def compile(source, filename, mode, flags=None, dont_inherit=None):
+    """Replacement for builtin compile() function"""
+    if flags is not None or dont_inherit is not None:
+        raise RuntimeError, "not implemented yet"
+
+    if mode == "single":
+        gen = Interactive(source, filename)
+    elif mode == "exec":
+        gen = Module(source, filename)
+    elif mode == "eval":
+        gen = Expression(source, filename)
+    else:
+        raise ValueError("compile() 3rd arg must be 'exec' or "
+                         "'eval' or 'single'")
+    gen.compile()
+    return gen.code
+
+class AbstractCompileMode:
+
+    mode = None # defined by subclass
+
+    def __init__(self, source, filename):
+        self.source = source
+        self.filename = filename
+        self.code = None
+
+    def _get_tree(self):
+        tree = parse(self.source, self.mode)
+        misc.set_filename(self.filename, tree)
+        syntax.check(tree)
+        return tree
+
+    def compile(self):
+        pass # implemented by subclass
+
+    def getCode(self):
+        return self.code
+
+class Expression(AbstractCompileMode):
+
+    mode = "eval"
+
+    def compile(self):
+        tree = self._get_tree()
+        gen = ExpressionCodeGenerator(tree)
+        self.code = gen.getCode()
+
+class Interactive(AbstractCompileMode):
+
+    mode = "single"
+
+    def compile(self):
+        tree = self._get_tree()
+        gen = InteractiveCodeGenerator(tree)
+        self.code = gen.getCode()
+
+class Module(AbstractCompileMode):
+
+    mode = "exec"
+
+    def compile(self, display=0):
+        tree = self._get_tree()
+        gen = ModuleCodeGenerator(tree)
+        if display:
+            import pprint
+            print pprint.pprint(tree)
+        self.code = gen.getCode()
+
+    def dump(self, f):
+        f.write(self.getPycHeader())
+        marshal.dump(self.code, f)
+
+    MAGIC = imp.get_magic()
+
+    def getPycHeader(self):
+        # compile.c uses marshal to write a long directly, with
+        # calling the interface that would also generate a 1-byte code
+        # to indicate the type of the value.  simplest way to get the
+        # same effect is to call marshal and then skip the code.
+        mtime = os.path.getmtime(self.filename)
+        mtime = struct.pack('<i', mtime)
+        return self.MAGIC + mtime
+
+class LocalNameFinder:
+    """Find local names in scope"""
+    def __init__(self, names=()):
+        self.names = misc.Set()
+        self.globals = misc.Set()
+        for name in names:
+            self.names.add(name)
+
+    # XXX list comprehensions and for loops
+
+    def getLocals(self):
+        for elt in self.globals.elements():
+            if self.names.has_elt(elt):
+                self.names.remove(elt)
+        return self.names
+
+    def visitDict(self, node):
+        pass
+
+    def visitGlobal(self, node):
+        for name in node.names:
+            self.globals.add(name)
+
+    def visitFunction(self, node):
+        self.names.add(node.name)
+
+    def visitLambda(self, node):
+        pass
+
+    def visitImport(self, node):
+        for name, alias in node.names:
+            self.names.add(alias or name)
+
+    def visitFrom(self, node):
+        for name, alias in node.names:
+            self.names.add(alias or name)
+
+    def visitClass(self, node):
+        self.names.add(node.name)
+
+    def visitAssName(self, node):
+        self.names.add(node.name)
+
+def is_constant_false(node):
+    if isinstance(node, ast.Const):
+        if not node.value:
+            return 1
+    return 0
+
+class CodeGenerator:
+    """Defines basic code generator for Python bytecode
+
+    This class is an abstract base class.  Concrete subclasses must
+    define an __init__() that defines self.graph and then calls the
+    __init__() defined in this class.
+
+    The concrete class must also define the class attributes
+    NameFinder, FunctionGen, and ClassGen.  These attributes can be
+    defined in the initClass() method, which is a hook for
+    initializing these methods after all the classes have been
+    defined.
+    """
+
+    optimized = 0 # is namespace access optimized?
+    __initialized = None
+    class_name = None # provide default for instance variable
+
+    def __init__(self):
+        if self.__initialized is None:
+            self.initClass()
+            self.__class__.__initialized = 1
+        self.checkClass()
+        self.locals = misc.Stack()
+        self.setups = misc.Stack()
+        self.last_lineno = None
+        self._setupGraphDelegation()
+        self._div_op = "BINARY_DIVIDE"
+
+        # XXX set flags based on future features
+        futures = self.get_module().futures
+        for feature in futures:
+            if feature == "division":
+                self.graph.setFlag(CO_FUTURE_DIVISION)
+                self._div_op = "BINARY_TRUE_DIVIDE"
+            elif feature == "absolute_import":
+                self.graph.setFlag(CO_FUTURE_ABSIMPORT)
+            elif feature == "with_statement":
+                self.graph.setFlag(CO_FUTURE_WITH_STATEMENT)
+
+    def initClass(self):
+        """This method is called once for each class"""
+
+    def checkClass(self):
+        """Verify that class is constructed correctly"""
+        try:
+            assert hasattr(self, 'graph')
+            assert getattr(self, 'NameFinder')
+            assert getattr(self, 'FunctionGen')
+            assert getattr(self, 'ClassGen')
+        except AssertionError, msg:
+            intro = "Bad class construction for %s" % self.__class__.__name__
+            raise AssertionError, intro
+
+    def _setupGraphDelegation(self):
+        self.emit = self.graph.emit
+        self.newBlock = self.graph.newBlock
+        self.startBlock = self.graph.startBlock
+        self.nextBlock = self.graph.nextBlock
+        self.setDocstring = self.graph.setDocstring
+
+    def getCode(self):
+        """Return a code object"""
+        return self.graph.getCode()
+
+    def mangle(self, name):
+        if self.class_name is not None:
+            return misc.mangle(name, self.class_name)
+        else:
+            return name
+
+    def parseSymbols(self, tree):
+        s = symbols.SymbolVisitor()
+        walk(tree, s)
+        return s.scopes
+
+    def get_module(self):
+        raise RuntimeError, "should be implemented by subclasses"
+
+    # Next five methods handle name access
+
+    def isLocalName(self, name):
+        return self.locals.top().has_elt(name)
+
+    def storeName(self, name):
+        self._nameOp('STORE', name)
+
+    def loadName(self, name):
+        self._nameOp('LOAD', name)
+
+    def delName(self, name):
+        self._nameOp('DELETE', name)
+
+    def _nameOp(self, prefix, name):
+        name = self.mangle(name)
+        scope = self.scope.check_name(name)
+        if scope == SC_LOCAL:
+            if not self.optimized:
+                self.emit(prefix + '_NAME', name)
+            else:
+                self.emit(prefix + '_FAST', name)
+        elif scope == SC_GLOBAL:
+            if not self.optimized:
+                self.emit(prefix + '_NAME', name)
+            else:
+                self.emit(prefix + '_GLOBAL', name)
+        elif scope == SC_FREE or scope == SC_CELL:
+            self.emit(prefix + '_DEREF', name)
+        else:
+            raise RuntimeError, "unsupported scope for var %s: %d" % \
+                  (name, scope)
+
+    def _implicitNameOp(self, prefix, name):
+        """Emit name ops for names generated implicitly by for loops
+
+        The interpreter generates names that start with a period or
+        dollar sign.  The symbol table ignores these names because
+        they aren't present in the program text.
+        """
+        if self.optimized:
+            self.emit(prefix + '_FAST', name)
+        else:
+            self.emit(prefix + '_NAME', name)
+
+    # The set_lineno() function and the explicit emit() calls for
+    # SET_LINENO below are only used to generate the line number table.
+    # As of Python 2.3, the interpreter does not have a SET_LINENO
+    # instruction.  pyassem treats SET_LINENO opcodes as a special case.
+
+    def set_lineno(self, node, force=False):
+        """Emit SET_LINENO if necessary.
+
+        The instruction is considered necessary if the node has a
+        lineno attribute and it is different than the last lineno
+        emitted.
+
+        Returns true if SET_LINENO was emitted.
+
+        There are no rules for when an AST node should have a lineno
+        attribute.  The transformer and AST code need to be reviewed
+        and a consistent policy implemented and documented.  Until
+        then, this method works around missing line numbers.
+        """
+        lineno = getattr(node, 'lineno', None)
+        if lineno is not None and (lineno != self.last_lineno
+                                   or force):
+            self.emit('SET_LINENO', lineno)
+            self.last_lineno = lineno
+            return True
+        return False
+
+    # The first few visitor methods handle nodes that generator new
+    # code objects.  They use class attributes to determine what
+    # specialized code generators to use.
+
+    NameFinder = LocalNameFinder
+    FunctionGen = None
+    ClassGen = None
+
+    def visitModule(self, node):
+        self.scopes = self.parseSymbols(node)
+        self.scope = self.scopes[node]
+        self.emit('SET_LINENO', 0)
+        if node.doc:
+            self.emit('LOAD_CONST', node.doc)
+            self.storeName('__doc__')
+        lnf = walk(node.node, self.NameFinder(), verbose=0)
+        self.locals.push(lnf.getLocals())
+        self.visit(node.node)
+        self.emit('LOAD_CONST', None)
+        self.emit('RETURN_VALUE')
+
+    def visitExpression(self, node):
+        self.set_lineno(node)
+        self.scopes = self.parseSymbols(node)
+        self.scope = self.scopes[node]
+        self.visit(node.node)
+        self.emit('RETURN_VALUE')
+
+    def visitFunction(self, node):
+        self._visitFuncOrLambda(node, isLambda=0)
+        if node.doc:
+            self.setDocstring(node.doc)
+        self.storeName(node.name)
+
+    def visitLambda(self, node):
+        self._visitFuncOrLambda(node, isLambda=1)
+
+    def _visitFuncOrLambda(self, node, isLambda=0):
+        if not isLambda and node.decorators:
+            for decorator in node.decorators.nodes:
+                self.visit(decorator)
+            ndecorators = len(node.decorators.nodes)
+        else:
+            ndecorators = 0
+
+        gen = self.FunctionGen(node, self.scopes, isLambda,
+                               self.class_name, self.get_module())
+        walk(node.code, gen)
+        gen.finish()
+        self.set_lineno(node)
+        for default in node.defaults:
+            self.visit(default)
+        self._makeClosure(gen, len(node.defaults))
+        for i in range(ndecorators):
+            self.emit('CALL_FUNCTION', 1)
+
+    def visitClass(self, node):
+        gen = self.ClassGen(node, self.scopes,
+                            self.get_module())
+        walk(node.code, gen)
+        gen.finish()
+        self.set_lineno(node)
+        self.emit('LOAD_CONST', node.name)
+        for base in node.bases:
+            self.visit(base)
+        self.emit('BUILD_TUPLE', len(node.bases))
+        self._makeClosure(gen, 0)
+        self.emit('CALL_FUNCTION', 0)
+        self.emit('BUILD_CLASS')
+        self.storeName(node.name)
+
+    # The rest are standard visitor methods
+
+    # The next few implement control-flow statements
+
+    def visitIf(self, node):
+        end = self.newBlock()
+        numtests = len(node.tests)
+        for i in range(numtests):
+            test, suite = node.tests[i]
+            if is_constant_false(test):
+                # XXX will need to check generator stuff here
+                continue
+            self.set_lineno(test)
+            self.visit(test)
+            nextTest = self.newBlock()
+            self.emit('JUMP_IF_FALSE', nextTest)
+            self.nextBlock()
+            self.emit('POP_TOP')
+            self.visit(suite)
+            self.emit('JUMP_FORWARD', end)
+            self.startBlock(nextTest)
+            self.emit('POP_TOP')
+        if node.else_:
+            self.visit(node.else_)
+        self.nextBlock(end)
+
+    def visitWhile(self, node):
+        self.set_lineno(node)
+
+        loop = self.newBlock()
+        else_ = self.newBlock()
+
+        after = self.newBlock()
+        self.emit('SETUP_LOOP', after)
+
+        self.nextBlock(loop)
+        self.setups.push((LOOP, loop))
+
+        self.set_lineno(node, force=True)
+        self.visit(node.test)
+        self.emit('JUMP_IF_FALSE', else_ or after)
+
+        self.nextBlock()
+        self.emit('POP_TOP')
+        self.visit(node.body)
+        self.emit('JUMP_ABSOLUTE', loop)
+
+        self.startBlock(else_) # or just the POPs if not else clause
+        self.emit('POP_TOP')
+        self.emit('POP_BLOCK')
+        self.setups.pop()
+        if node.else_:
+            self.visit(node.else_)
+        self.nextBlock(after)
+
+    def visitFor(self, node):
+        start = self.newBlock()
+        anchor = self.newBlock()
+        after = self.newBlock()
+        self.setups.push((LOOP, start))
+
+        self.set_lineno(node)
+        self.emit('SETUP_LOOP', after)
+        self.visit(node.list)
+        self.emit('GET_ITER')
+
+        self.nextBlock(start)
+        self.set_lineno(node, force=1)
+        self.emit('FOR_ITER', anchor)
+        self.visit(node.assign)
+        self.visit(node.body)
+        self.emit('JUMP_ABSOLUTE', start)
+        self.nextBlock(anchor)
+        self.emit('POP_BLOCK')
+        self.setups.pop()
+        if node.else_:
+            self.visit(node.else_)
+        self.nextBlock(after)
+
+    def visitBreak(self, node):
+        if not self.setups:
+            raise SyntaxError, "'break' outside loop (%s, %d)" % \
+                  (node.filename, node.lineno)
+        self.set_lineno(node)
+        self.emit('BREAK_LOOP')
+
+    def visitContinue(self, node):
+        if not self.setups:
+            raise SyntaxError, "'continue' outside loop (%s, %d)" % \
+                  (node.filename, node.lineno)
+        kind, block = self.setups.top()
+        if kind == LOOP:
+            self.set_lineno(node)
+            self.emit('JUMP_ABSOLUTE', block)
+            self.nextBlock()
+        elif kind == EXCEPT or kind == TRY_FINALLY:
+            self.set_lineno(node)
+            # find the block that starts the loop
+            top = len(self.setups)
+            while top > 0:
+                top = top - 1
+                kind, loop_block = self.setups[top]
+                if kind == LOOP:
+                    break
+            if kind != LOOP:
+                raise SyntaxError, "'continue' outside loop (%s, %d)" % \
+                      (node.filename, node.lineno)
+            self.emit('CONTINUE_LOOP', loop_block)
+            self.nextBlock()
+        elif kind == END_FINALLY:
+            msg = "'continue' not allowed inside 'finally' clause (%s, %d)"
+            raise SyntaxError, msg % (node.filename, node.lineno)
+
+    def visitTest(self, node, jump):
+        end = self.newBlock()
+        for child in node.nodes[:-1]:
+            self.visit(child)
+            self.emit(jump, end)
+            self.nextBlock()
+            self.emit('POP_TOP')
+        self.visit(node.nodes[-1])
+        self.nextBlock(end)
+
+    def visitAnd(self, node):
+        self.visitTest(node, 'JUMP_IF_FALSE')
+
+    def visitOr(self, node):
+        self.visitTest(node, 'JUMP_IF_TRUE')
+
+    def visitIfExp(self, node):
+        endblock = self.newBlock()
+        elseblock = self.newBlock()
+        self.visit(node.test)
+        self.emit('JUMP_IF_FALSE', elseblock)
+        self.emit('POP_TOP')
+        self.visit(node.then)
+        self.emit('JUMP_FORWARD', endblock)
+        self.nextBlock(elseblock)
+        self.emit('POP_TOP')
+        self.visit(node.else_)
+        self.nextBlock(endblock)
+
+    def visitCompare(self, node):
+        self.visit(node.expr)
+        cleanup = self.newBlock()
+        for op, code in node.ops[:-1]:
+            self.visit(code)
+            self.emit('DUP_TOP')
+            self.emit('ROT_THREE')
+            self.emit('COMPARE_OP', op)
+            self.emit('JUMP_IF_FALSE', cleanup)
+            self.nextBlock()
+            self.emit('POP_TOP')
+        # now do the last comparison
+        if node.ops:
+            op, code = node.ops[-1]
+            self.visit(code)
+            self.emit('COMPARE_OP', op)
+        if len(node.ops) > 1:
+            end = self.newBlock()
+            self.emit('JUMP_FORWARD', end)
+            self.startBlock(cleanup)
+            self.emit('ROT_TWO')
+            self.emit('POP_TOP')
+            self.nextBlock(end)
+
+    # list comprehensions
+    __list_count = 0
+
+    def visitListComp(self, node):
+        self.set_lineno(node)
+        # setup list
+        append = "$append%d" % self.__list_count
+        self.__list_count = self.__list_count + 1
+        self.emit('BUILD_LIST', 0)
+        self.emit('DUP_TOP')
+        self.emit('LOAD_ATTR', 'append')
+        self._implicitNameOp('STORE', append)
+
+        stack = []
+        for i, for_ in zip(range(len(node.quals)), node.quals):
+            start, anchor = self.visit(for_)
+            cont = None
+            for if_ in for_.ifs:
+                if cont is None:
+                    cont = self.newBlock()
+                self.visit(if_, cont)
+            stack.insert(0, (start, cont, anchor))
+
+        self._implicitNameOp('LOAD', append)
+        self.visit(node.expr)
+        self.emit('CALL_FUNCTION', 1)
+        self.emit('POP_TOP')
+
+        for start, cont, anchor in stack:
+            if cont:
+                skip_one = self.newBlock()
+                self.emit('JUMP_FORWARD', skip_one)
+                self.startBlock(cont)
+                self.emit('POP_TOP')
+                self.nextBlock(skip_one)
+            self.emit('JUMP_ABSOLUTE', start)
+            self.startBlock(anchor)
+        self._implicitNameOp('DELETE', append)
+
+        self.__list_count = self.__list_count - 1
+
+    def visitListCompFor(self, node):
+        start = self.newBlock()
+        anchor = self.newBlock()
+
+        self.visit(node.list)
+        self.emit('GET_ITER')
+        self.nextBlock(start)
+        self.set_lineno(node, force=True)
+        self.emit('FOR_ITER', anchor)
+        self.nextBlock()
+        self.visit(node.assign)
+        return start, anchor
+
+    def visitListCompIf(self, node, branch):
+        self.set_lineno(node, force=True)
+        self.visit(node.test)
+        self.emit('JUMP_IF_FALSE', branch)
+        self.newBlock()
+        self.emit('POP_TOP')
+
+    def _makeClosure(self, gen, args):
+        frees = gen.scope.get_free_vars()
+        if frees:
+            for name in frees:
+                self.emit('LOAD_CLOSURE', name)
+            self.emit('BUILD_TUPLE', len(frees))
+            self.emit('LOAD_CONST', gen)
+            self.emit('MAKE_CLOSURE', args)
+        else:
+            self.emit('LOAD_CONST', gen)
+            self.emit('MAKE_FUNCTION', args)
+
+    def visitGenExpr(self, node):
+        gen = GenExprCodeGenerator(node, self.scopes, self.class_name,
+                                   self.get_module())
+        walk(node.code, gen)
+        gen.finish()
+        self.set_lineno(node)
+        self._makeClosure(gen, 0)
+        # precomputation of outmost iterable
+        self.visit(node.code.quals[0].iter)
+        self.emit('GET_ITER')
+        self.emit('CALL_FUNCTION', 1)
+
+    def visitGenExprInner(self, node):
+        self.set_lineno(node)
+        # setup list
+
+        stack = []
+        for i, for_ in zip(range(len(node.quals)), node.quals):
+            start, anchor, end = self.visit(for_)
+            cont = None
+            for if_ in for_.ifs:
+                if cont is None:
+                    cont = self.newBlock()
+                self.visit(if_, cont)
+            stack.insert(0, (start, cont, anchor, end))
+
+        self.visit(node.expr)
+        self.emit('YIELD_VALUE')
+        self.emit('POP_TOP')
+
+        for start, cont, anchor, end in stack:
+            if cont:
+                skip_one = self.newBlock()
+                self.emit('JUMP_FORWARD', skip_one)
+                self.startBlock(cont)
+                self.emit('POP_TOP')
+                self.nextBlock(skip_one)
+            self.emit('JUMP_ABSOLUTE', start)
+            self.startBlock(anchor)
+            self.emit('POP_BLOCK')
+            self.setups.pop()
+            self.startBlock(end)
+
+        self.emit('LOAD_CONST', None)
+
+    def visitGenExprFor(self, node):
+        start = self.newBlock()
+        anchor = self.newBlock()
+        end = self.newBlock()
+
+        self.setups.push((LOOP, start))
+        self.emit('SETUP_LOOP', end)
+
+        if node.is_outmost:
+            self.loadName('.0')
+        else:
+            self.visit(node.iter)
+            self.emit('GET_ITER')
+
+        self.nextBlock(start)
+        self.set_lineno(node, force=True)
+        self.emit('FOR_ITER', anchor)
+        self.nextBlock()
+        self.visit(node.assign)
+        return start, anchor, end
+
+    def visitGenExprIf(self, node, branch):
+        self.set_lineno(node, force=True)
+        self.visit(node.test)
+        self.emit('JUMP_IF_FALSE', branch)
+        self.newBlock()
+        self.emit('POP_TOP')
+
+    # exception related
+
+    def visitAssert(self, node):
+        # XXX would be interesting to implement this via a
+        # transformation of the AST before this stage
+        if __debug__:
+            end = self.newBlock()
+            self.set_lineno(node)
+            # XXX AssertionError appears to be special case -- it is always
+            # loaded as a global even if there is a local name.  I guess this
+            # is a sort of renaming op.
+            self.nextBlock()
+            self.visit(node.test)
+            self.emit('JUMP_IF_TRUE', end)
+            self.nextBlock()
+            self.emit('POP_TOP')
+            self.emit('LOAD_GLOBAL', 'AssertionError')
+            if node.fail:
+                self.visit(node.fail)
+                self.emit('RAISE_VARARGS', 2)
+            else:
+                self.emit('RAISE_VARARGS', 1)
+            self.nextBlock(end)
+            self.emit('POP_TOP')
+
+    def visitRaise(self, node):
+        self.set_lineno(node)
+        n = 0
+        if node.expr1:
+            self.visit(node.expr1)
+            n = n + 1
+        if node.expr2:
+            self.visit(node.expr2)
+            n = n + 1
+        if node.expr3:
+            self.visit(node.expr3)
+            n = n + 1
+        self.emit('RAISE_VARARGS', n)
+
+    def visitTryExcept(self, node):
+        body = self.newBlock()
+        handlers = self.newBlock()
+        end = self.newBlock()
+        if node.else_:
+            lElse = self.newBlock()
+        else:
+            lElse = end
+        self.set_lineno(node)
+        self.emit('SETUP_EXCEPT', handlers)
+        self.nextBlock(body)
+        self.setups.push((EXCEPT, body))
+        self.visit(node.body)
+        self.emit('POP_BLOCK')
+        self.setups.pop()
+        self.emit('JUMP_FORWARD', lElse)
+        self.startBlock(handlers)
+
+        last = len(node.handlers) - 1
+        for i in range(len(node.handlers)):
+            expr, target, body = node.handlers[i]
+            self.set_lineno(expr)
+            if expr:
+                self.emit('DUP_TOP')
+                self.visit(expr)
+                self.emit('COMPARE_OP', 'exception match')
+                next = self.newBlock()
+                self.emit('JUMP_IF_FALSE', next)
+                self.nextBlock()
+                self.emit('POP_TOP')
+            self.emit('POP_TOP')
+            if target:
+                self.visit(target)
+            else:
+                self.emit('POP_TOP')
+            self.emit('POP_TOP')
+            self.visit(body)
+            self.emit('JUMP_FORWARD', end)
+            if expr:
+                self.nextBlock(next)
+            else:
+                self.nextBlock()
+            if expr: # XXX
+                self.emit('POP_TOP')
+        self.emit('END_FINALLY')
+        if node.else_:
+            self.nextBlock(lElse)
+            self.visit(node.else_)
+        self.nextBlock(end)
+
+    def visitTryFinally(self, node):
+        body = self.newBlock()
+        final = self.newBlock()
+        self.set_lineno(node)
+        self.emit('SETUP_FINALLY', final)
+        self.nextBlock(body)
+        self.setups.push((TRY_FINALLY, body))
+        self.visit(node.body)
+        self.emit('POP_BLOCK')
+        self.setups.pop()
+        self.emit('LOAD_CONST', None)
+        self.nextBlock(final)
+        self.setups.push((END_FINALLY, final))
+        self.visit(node.final)
+        self.emit('END_FINALLY')
+        self.setups.pop()
+
+    __with_count = 0
+
+    def visitWith(self, node):
+        body = self.newBlock()
+        final = self.newBlock()
+        exitvar = "$exit%d" % self.__with_count
+        valuevar = "$value%d" % self.__with_count
+        self.__with_count += 1
+        self.set_lineno(node)
+        self.visit(node.expr)
+        self.emit('DUP_TOP')
+        self.emit('LOAD_ATTR', '__exit__')
+        self._implicitNameOp('STORE', exitvar)
+        self.emit('LOAD_ATTR', '__enter__')
+        self.emit('CALL_FUNCTION', 0)
+        if node.vars is None:
+            self.emit('POP_TOP')
+        else:
+            self._implicitNameOp('STORE', valuevar)
+        self.emit('SETUP_FINALLY', final)
+        self.nextBlock(body)
+        self.setups.push((TRY_FINALLY, body))
+        if node.vars is not None:
+            self._implicitNameOp('LOAD', valuevar)
+            self._implicitNameOp('DELETE', valuevar)
+            self.visit(node.vars)
+        self.visit(node.body)
+        self.emit('POP_BLOCK')
+        self.setups.pop()
+        self.emit('LOAD_CONST', None)
+        self.nextBlock(final)
+        self.setups.push((END_FINALLY, final))
+        self._implicitNameOp('LOAD', exitvar)
+        self._implicitNameOp('DELETE', exitvar)
+        self.emit('WITH_CLEANUP')
+        self.emit('END_FINALLY')
+        self.setups.pop()
+        self.__with_count -= 1
+
+    # misc
+
+    def visitDiscard(self, node):
+        self.set_lineno(node)
+        self.visit(node.expr)
+        self.emit('POP_TOP')
+
+    def visitConst(self, node):
+        self.emit('LOAD_CONST', node.value)
+
+    def visitKeyword(self, node):
+        self.emit('LOAD_CONST', node.name)
+        self.visit(node.expr)
+
+    def visitGlobal(self, node):
+        # no code to generate
+        pass
+
+    def visitName(self, node):
+        self.set_lineno(node)
+        self.loadName(node.name)
+
+    def visitPass(self, node):
+        self.set_lineno(node)
+
+    def visitImport(self, node):
+        self.set_lineno(node)
+        level = 0 if self.graph.checkFlag(CO_FUTURE_ABSIMPORT) else -1
+        for name, alias in node.names:
+            if VERSION > 1:
+                self.emit('LOAD_CONST', level)
+                self.emit('LOAD_CONST', None)
+            self.emit('IMPORT_NAME', name)
+            mod = name.split(".")[0]
+            if alias:
+                self._resolveDots(name)
+                self.storeName(alias)
+            else:
+                self.storeName(mod)
+
+    def visitFrom(self, node):
+        self.set_lineno(node)
+        level = node.level
+        if level == 0 and not self.graph.checkFlag(CO_FUTURE_ABSIMPORT):
+            level = -1
+        fromlist = map(lambda (name, alias): name, node.names)
+        if VERSION > 1:
+            self.emit('LOAD_CONST', level)
+            self.emit('LOAD_CONST', tuple(fromlist))
+        self.emit('IMPORT_NAME', node.modname)
+        for name, alias in node.names:
+            if VERSION > 1:
+                if name == '*':
+                    self.namespace = 0
+                    self.emit('IMPORT_STAR')
+                    # There can only be one name w/ from ... import *
+                    assert len(node.names) == 1
+                    return
+                else:
+                    self.emit('IMPORT_FROM', name)
+                    self._resolveDots(name)
+                    self.storeName(alias or name)
+            else:
+                self.emit('IMPORT_FROM', name)
+        self.emit('POP_TOP')
+
+    def _resolveDots(self, name):
+        elts = name.split(".")
+        if len(elts) == 1:
+            return
+        for elt in elts[1:]:
+            self.emit('LOAD_ATTR', elt)
+
+    def visitGetattr(self, node):
+        self.visit(node.expr)
+        self.emit('LOAD_ATTR', self.mangle(node.attrname))
+
+    # next five implement assignments
+
+    def visitAssign(self, node):
+        self.set_lineno(node)
+        self.visit(node.expr)
+        dups = len(node.nodes) - 1
+        for i in range(len(node.nodes)):
+            elt = node.nodes[i]
+            if i < dups:
+                self.emit('DUP_TOP')
+            if isinstance(elt, ast.Node):
+                self.visit(elt)
+
+    def visitAssName(self, node):
+        if node.flags == 'OP_ASSIGN':
+            self.storeName(node.name)
+        elif node.flags == 'OP_DELETE':
+            self.set_lineno(node)
+            self.delName(node.name)
+        else:
+            print "oops", node.flags
+
+    def visitAssAttr(self, node):
+        self.visit(node.expr)
+        if node.flags == 'OP_ASSIGN':
+            self.emit('STORE_ATTR', self.mangle(node.attrname))
+        elif node.flags == 'OP_DELETE':
+            self.emit('DELETE_ATTR', self.mangle(node.attrname))
+        else:
+            print "warning: unexpected flags:", node.flags
+            print node
+
+    def _visitAssSequence(self, node, op='UNPACK_SEQUENCE'):
+        if findOp(node) != 'OP_DELETE':
+            self.emit(op, len(node.nodes))
+        for child in node.nodes:
+            self.visit(child)
+
+    if VERSION > 1:
+        visitAssTuple = _visitAssSequence
+        visitAssList = _visitAssSequence
+    else:
+        def visitAssTuple(self, node):
+            self._visitAssSequence(node, 'UNPACK_TUPLE')
+
+        def visitAssList(self, node):
+            self._visitAssSequence(node, 'UNPACK_LIST')
+
+    # augmented assignment
+
+    def visitAugAssign(self, node):
+        self.set_lineno(node)
+        aug_node = wrap_aug(node.node)
+        self.visit(aug_node, "load")
+        self.visit(node.expr)
+        self.emit(self._augmented_opcode[node.op])
+        self.visit(aug_node, "store")
+
+    _augmented_opcode = {
+        '+=' : 'INPLACE_ADD',
+        '-=' : 'INPLACE_SUBTRACT',
+        '*=' : 'INPLACE_MULTIPLY',
+        '/=' : 'INPLACE_DIVIDE',
+        '//=': 'INPLACE_FLOOR_DIVIDE',
+        '%=' : 'INPLACE_MODULO',
+        '**=': 'INPLACE_POWER',
+        '>>=': 'INPLACE_RSHIFT',
+        '<<=': 'INPLACE_LSHIFT',
+        '&=' : 'INPLACE_AND',
+        '^=' : 'INPLACE_XOR',
+        '|=' : 'INPLACE_OR',
+        }
+
+    def visitAugName(self, node, mode):
+        if mode == "load":
+            self.loadName(node.name)
+        elif mode == "store":
+            self.storeName(node.name)
+
+    def visitAugGetattr(self, node, mode):
+        if mode == "load":
+            self.visit(node.expr)
+            self.emit('DUP_TOP')
+            self.emit('LOAD_ATTR', self.mangle(node.attrname))
+        elif mode == "store":
+            self.emit('ROT_TWO')
+            self.emit('STORE_ATTR', self.mangle(node.attrname))
+
+    def visitAugSlice(self, node, mode):
+        if mode == "load":
+            self.visitSlice(node, 1)
+        elif mode == "store":
+            slice = 0
+            if node.lower:
+                slice = slice | 1
+            if node.upper:
+                slice = slice | 2
+            if slice == 0:
+                self.emit('ROT_TWO')
+            elif slice == 3:
+                self.emit('ROT_FOUR')
+            else:
+                self.emit('ROT_THREE')
+            self.emit('STORE_SLICE+%d' % slice)
+
+    def visitAugSubscript(self, node, mode):
+        if mode == "load":
+            self.visitSubscript(node, 1)
+        elif mode == "store":
+            self.emit('ROT_THREE')
+            self.emit('STORE_SUBSCR')
+
+    def visitExec(self, node):
+        self.visit(node.expr)
+        if node.locals is None:
+            self.emit('LOAD_CONST', None)
+        else:
+            self.visit(node.locals)
+        if node.globals is None:
+            self.emit('DUP_TOP')
+        else:
+            self.visit(node.globals)
+        self.emit('EXEC_STMT')
+
+    def visitCallFunc(self, node):
+        pos = 0
+        kw = 0
+        self.set_lineno(node)
+        self.visit(node.node)
+        for arg in node.args:
+            self.visit(arg)
+            if isinstance(arg, ast.Keyword):
+                kw = kw + 1
+            else:
+                pos = pos + 1
+        if node.star_args is not None:
+            self.visit(node.star_args)
+        if node.dstar_args is not None:
+            self.visit(node.dstar_args)
+        have_star = node.star_args is not None
+        have_dstar = node.dstar_args is not None
+        opcode = callfunc_opcode_info[have_star, have_dstar]
+        self.emit(opcode, kw << 8 | pos)
+
+    def visitPrint(self, node, newline=0):
+        self.set_lineno(node)
+        if node.dest:
+            self.visit(node.dest)
+        for child in node.nodes:
+            if node.dest:
+                self.emit('DUP_TOP')
+            self.visit(child)
+            if node.dest:
+                self.emit('ROT_TWO')
+                self.emit('PRINT_ITEM_TO')
+            else:
+                self.emit('PRINT_ITEM')
+        if node.dest and not newline:
+            self.emit('POP_TOP')
+
+    def visitPrintnl(self, node):
+        self.visitPrint(node, newline=1)
+        if node.dest:
+            self.emit('PRINT_NEWLINE_TO')
+        else:
+            self.emit('PRINT_NEWLINE')
+
+    def visitReturn(self, node):
+        self.set_lineno(node)
+        self.visit(node.value)
+        self.emit('RETURN_VALUE')
+
+    def visitYield(self, node):
+        self.set_lineno(node)
+        self.visit(node.value)
+        self.emit('YIELD_VALUE')
+
+    # slice and subscript stuff
+
+    def visitSlice(self, node, aug_flag=None):
+        # aug_flag is used by visitAugSlice
+        self.visit(node.expr)
+        slice = 0
+        if node.lower:
+            self.visit(node.lower)
+            slice = slice | 1
+        if node.upper:
+            self.visit(node.upper)
+            slice = slice | 2
+        if aug_flag:
+            if slice == 0:
+                self.emit('DUP_TOP')
+            elif slice == 3:
+                self.emit('DUP_TOPX', 3)
+            else:
+                self.emit('DUP_TOPX', 2)
+        if node.flags == 'OP_APPLY':
+            self.emit('SLICE+%d' % slice)
+        elif node.flags == 'OP_ASSIGN':
+            self.emit('STORE_SLICE+%d' % slice)
+        elif node.flags == 'OP_DELETE':
+            self.emit('DELETE_SLICE+%d' % slice)
+        else:
+            print "weird slice", node.flags
+            raise
+
+    def visitSubscript(self, node, aug_flag=None):
+        self.visit(node.expr)
+        for sub in node.subs:
+            self.visit(sub)
+        if len(node.subs) > 1:
+            self.emit('BUILD_TUPLE', len(node.subs))
+        if aug_flag:
+            self.emit('DUP_TOPX', 2)
+        if node.flags == 'OP_APPLY':
+            self.emit('BINARY_SUBSCR')
+        elif node.flags == 'OP_ASSIGN':
+            self.emit('STORE_SUBSCR')
+        elif node.flags == 'OP_DELETE':
+            self.emit('DELETE_SUBSCR')
+
+    # binary ops
+
+    def binaryOp(self, node, op):
+        self.visit(node.left)
+        self.visit(node.right)
+        self.emit(op)
+
+    def visitAdd(self, node):
+        return self.binaryOp(node, 'BINARY_ADD')
+
+    def visitSub(self, node):
+        return self.binaryOp(node, 'BINARY_SUBTRACT')
+
+    def visitMul(self, node):
+        return self.binaryOp(node, 'BINARY_MULTIPLY')
+
+    def visitDiv(self, node):
+        return self.binaryOp(node, self._div_op)
+
+    def visitFloorDiv(self, node):
+        return self.binaryOp(node, 'BINARY_FLOOR_DIVIDE')
+
+    def visitMod(self, node):
+        return self.binaryOp(node, 'BINARY_MODULO')
+
+    def visitPower(self, node):
+        return self.binaryOp(node, 'BINARY_POWER')
+
+    def visitLeftShift(self, node):
+        return self.binaryOp(node, 'BINARY_LSHIFT')
+
+    def visitRightShift(self, node):
+        return self.binaryOp(node, 'BINARY_RSHIFT')
+
+    # unary ops
+
+    def unaryOp(self, node, op):
+        self.visit(node.expr)
+        self.emit(op)
+
+    def visitInvert(self, node):
+        return self.unaryOp(node, 'UNARY_INVERT')
+
+    def visitUnarySub(self, node):
+        return self.unaryOp(node, 'UNARY_NEGATIVE')
+
+    def visitUnaryAdd(self, node):
+        return self.unaryOp(node, 'UNARY_POSITIVE')
+
+    def visitUnaryInvert(self, node):
+        return self.unaryOp(node, 'UNARY_INVERT')
+
+    def visitNot(self, node):
+        return self.unaryOp(node, 'UNARY_NOT')
+
+    def visitBackquote(self, node):
+        return self.unaryOp(node, 'UNARY_CONVERT')
+
+    # bit ops
+
+    def bitOp(self, nodes, op):
+        self.visit(nodes[0])
+        for node in nodes[1:]:
+            self.visit(node)
+            self.emit(op)
+
+    def visitBitand(self, node):
+        return self.bitOp(node.nodes, 'BINARY_AND')
+
+    def visitBitor(self, node):
+        return self.bitOp(node.nodes, 'BINARY_OR')
+
+    def visitBitxor(self, node):
+        return self.bitOp(node.nodes, 'BINARY_XOR')
+
+    # object constructors
+
+    def visitEllipsis(self, node):
+        self.emit('LOAD_CONST', Ellipsis)
+
+    def visitTuple(self, node):
+        self.set_lineno(node)
+        for elt in node.nodes:
+            self.visit(elt)
+        self.emit('BUILD_TUPLE', len(node.nodes))
+
+    def visitList(self, node):
+        self.set_lineno(node)
+        for elt in node.nodes:
+            self.visit(elt)
+        self.emit('BUILD_LIST', len(node.nodes))
+
+    def visitSliceobj(self, node):
+        for child in node.nodes:
+            self.visit(child)
+        self.emit('BUILD_SLICE', len(node.nodes))
+
+    def visitDict(self, node):
+        self.set_lineno(node)
+        self.emit('BUILD_MAP', 0)
+        for k, v in node.items:
+            self.emit('DUP_TOP')
+            self.visit(k)
+            self.visit(v)
+            self.emit('ROT_THREE')
+            self.emit('STORE_SUBSCR')
+
+class NestedScopeMixin:
+    """Defines initClass() for nested scoping (Python 2.2-compatible)"""
+    def initClass(self):
+        self.__class__.NameFinder = LocalNameFinder
+        self.__class__.FunctionGen = FunctionCodeGenerator
+        self.__class__.ClassGen = ClassCodeGenerator
+
+class ModuleCodeGenerator(NestedScopeMixin, CodeGenerator):
+    __super_init = CodeGenerator.__init__
+
+    scopes = None
+
+    def __init__(self, tree):
+        self.graph = pyassem.PyFlowGraph("<module>", tree.filename)
+        self.futures = future.find_futures(tree)
+        self.__super_init()
+        walk(tree, self)
+
+    def get_module(self):
+        return self
+
+class ExpressionCodeGenerator(NestedScopeMixin, CodeGenerator):
+    __super_init = CodeGenerator.__init__
+
+    scopes = None
+    futures = ()
+
+    def __init__(self, tree):
+        self.graph = pyassem.PyFlowGraph("<expression>", tree.filename)
+        self.__super_init()
+        walk(tree, self)
+
+    def get_module(self):
+        return self
+
+class InteractiveCodeGenerator(NestedScopeMixin, CodeGenerator):
+
+    __super_init = CodeGenerator.__init__
+
+    scopes = None
+    futures = ()
+
+    def __init__(self, tree):
+        self.graph = pyassem.PyFlowGraph("<interactive>", tree.filename)
+        self.__super_init()
+        self.set_lineno(tree)
+        walk(tree, self)
+        self.emit('RETURN_VALUE')
+
+    def get_module(self):
+        return self
+
+    def visitDiscard(self, node):
+        # XXX Discard means it's an expression.  Perhaps this is a bad
+        # name.
+        self.visit(node.expr)
+        self.emit('PRINT_EXPR')
+
+class AbstractFunctionCode:
+    optimized = 1
+    lambdaCount = 0
+
+    def __init__(self, func, scopes, isLambda, class_name, mod):
+        self.class_name = class_name
+        self.module = mod
+        if isLambda:
+            klass = FunctionCodeGenerator
+            name = "<lambda.%d>" % klass.lambdaCount
+            klass.lambdaCount = klass.lambdaCount + 1
+        else:
+            name = func.name
+
+        args, hasTupleArg = generateArgList(func.argnames)
+        self.graph = pyassem.PyFlowGraph(name, func.filename, args,
+                                         optimized=1)
+        self.isLambda = isLambda
+        self.super_init()
+
+        if not isLambda and func.doc:
+            self.setDocstring(func.doc)
+
+        lnf = walk(func.code, self.NameFinder(args), verbose=0)
+        self.locals.push(lnf.getLocals())
+        if func.varargs:
+            self.graph.setFlag(CO_VARARGS)
+        if func.kwargs:
+            self.graph.setFlag(CO_VARKEYWORDS)
+        self.set_lineno(func)
+        if hasTupleArg:
+            self.generateArgUnpack(func.argnames)
+
+    def get_module(self):
+        return self.module
+
+    def finish(self):
+        self.graph.startExitBlock()
+        if not self.isLambda:
+            self.emit('LOAD_CONST', None)
+        self.emit('RETURN_VALUE')
+
+    def generateArgUnpack(self, args):
+        for i in range(len(args)):
+            arg = args[i]
+            if isinstance(arg, tuple):
+                self.emit('LOAD_FAST', '.%d' % (i * 2))
+                self.unpackSequence(arg)
+
+    def unpackSequence(self, tup):
+        if VERSION > 1:
+            self.emit('UNPACK_SEQUENCE', len(tup))
+        else:
+            self.emit('UNPACK_TUPLE', len(tup))
+        for elt in tup:
+            if isinstance(elt, tuple):
+                self.unpackSequence(elt)
+            else:
+                self._nameOp('STORE', elt)
+
+    unpackTuple = unpackSequence
+
+class FunctionCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
+                            CodeGenerator):
+    super_init = CodeGenerator.__init__ # call be other init
+    scopes = None
+
+    __super_init = AbstractFunctionCode.__init__
+
+    def __init__(self, func, scopes, isLambda, class_name, mod):
+        self.scopes = scopes
+        self.scope = scopes[func]
+        self.__super_init(func, scopes, isLambda, class_name, mod)
+        self.graph.setFreeVars(self.scope.get_free_vars())
+        self.graph.setCellVars(self.scope.get_cell_vars())
+        if self.scope.generator is not None:
+            self.graph.setFlag(CO_GENERATOR)
+
+class GenExprCodeGenerator(NestedScopeMixin, AbstractFunctionCode,
+                           CodeGenerator):
+    super_init = CodeGenerator.__init__ # call be other init
+    scopes = None
+
+    __super_init = AbstractFunctionCode.__init__
+
+    def __init__(self, gexp, scopes, class_name, mod):
+        self.scopes = scopes
+        self.scope = scopes[gexp]
+        self.__super_init(gexp, scopes, 1, class_name, mod)
+        self.graph.setFreeVars(self.scope.get_free_vars())
+        self.graph.setCellVars(self.scope.get_cell_vars())
+        self.graph.setFlag(CO_GENERATOR)
+
+class AbstractClassCode:
+
+    def __init__(self, klass, scopes, module):
+        self.class_name = klass.name
+        self.module = module
+        self.graph = pyassem.PyFlowGraph(klass.name, klass.filename,
+                                           optimized=0, klass=1)
+        self.super_init()
+        lnf = walk(klass.code, self.NameFinder(), verbose=0)
+        self.locals.push(lnf.getLocals())
+        self.graph.setFlag(CO_NEWLOCALS)
+        if klass.doc:
+            self.setDocstring(klass.doc)
+
+    def get_module(self):
+        return self.module
+
+    def finish(self):
+        self.graph.startExitBlock()
+        self.emit('LOAD_LOCALS')
+        self.emit('RETURN_VALUE')
+
+class ClassCodeGenerator(NestedScopeMixin, AbstractClassCode, CodeGenerator):
+    super_init = CodeGenerator.__init__
+    scopes = None
+
+    __super_init = AbstractClassCode.__init__
+
+    def __init__(self, klass, scopes, module):
+        self.scopes = scopes
+        self.scope = scopes[klass]
+        self.__super_init(klass, scopes, module)
+        self.graph.setFreeVars(self.scope.get_free_vars())
+        self.graph.setCellVars(self.scope.get_cell_vars())
+        self.set_lineno(klass)
+        self.emit("LOAD_GLOBAL", "__name__")
+        self.storeName("__module__")
+        if klass.doc:
+            self.emit("LOAD_CONST", klass.doc)
+            self.storeName('__doc__')
+
+def generateArgList(arglist):
+    """Generate an arg list marking TupleArgs"""
+    args = []
+    extra = []
+    count = 0
+    for i in range(len(arglist)):
+        elt = arglist[i]
+        if isinstance(elt, str):
+            args.append(elt)
+        elif isinstance(elt, tuple):
+            args.append(TupleArg(i * 2, elt))
+            extra.extend(misc.flatten(elt))
+            count = count + 1
+        else:
+            raise ValueError, "unexpect argument type:", elt
+    return args + extra, count
+
+def findOp(node):
+    """Find the op (DELETE, LOAD, STORE) in an AssTuple tree"""
+    v = OpFinder()
+    walk(node, v, verbose=0)
+    return v.op
+
+class OpFinder:
+    def __init__(self):
+        self.op = None
+    def visitAssName(self, node):
+        if self.op is None:
+            self.op = node.flags
+        elif self.op != node.flags:
+            raise ValueError, "mixed ops in stmt"
+    visitAssAttr = visitAssName
+    visitSubscript = visitAssName
+
+class Delegator:
+    """Base class to support delegation for augmented assignment nodes
+
+    To generator code for augmented assignments, we use the following
+    wrapper classes.  In visitAugAssign, the left-hand expression node
+    is visited twice.  The first time the visit uses the normal method
+    for that node .  The second time the visit uses a different method
+    that generates the appropriate code to perform the assignment.
+    These delegator classes wrap the original AST nodes in order to
+    support the variant visit methods.
+    """
+    def __init__(self, obj):
+        self.obj = obj
+
+    def __getattr__(self, attr):
+        return getattr(self.obj, attr)
+
+class AugGetattr(Delegator):
+    pass
+
+class AugName(Delegator):
+    pass
+
+class AugSlice(Delegator):
+    pass
+
+class AugSubscript(Delegator):
+    pass
+
+wrapper = {
+    ast.Getattr: AugGetattr,
+    ast.Name: AugName,
+    ast.Slice: AugSlice,
+    ast.Subscript: AugSubscript,
+    }
+
+def wrap_aug(node):
+    return wrapper[node.__class__](node)
+
+if __name__ == "__main__":
+    for file in sys.argv[1:]:
+        compileFile(file)