Preliminary support for nested scopes

XXX Still doesn't work right for classes
XXX Still doesn't do sufficient error checking
diff --git a/Lib/compiler/pyassem.py b/Lib/compiler/pyassem.py
index 43bf6f4..447a8e7 100644
--- a/Lib/compiler/pyassem.py
+++ b/Lib/compiler/pyassem.py
@@ -99,12 +99,6 @@
         if not self.exit in order:
             order.append(self.exit)
 
-##        for b in order:
-##            print repr(b)
-##            print "\t", b.get_children()
-##            print b
-##            print
-            
         return order
 
     def getBlocks(self):
@@ -222,6 +216,7 @@
 CO_NEWLOCALS = 0x0002
 CO_VARARGS = 0x0004
 CO_VARKEYWORDS = 0x0008
+CO_NESTED = 0x0010
 
 # the FlowGraph is transformed in place; it exists in one of these states
 RAW = "RAW"
@@ -245,6 +240,15 @@
             self.flags = 0
         self.consts = []
         self.names = []
+        # Free variables found by the symbol table scan, including
+        # variables used only in nested scopes, are included here.
+        self.freevars = []
+        self.cellvars = []
+        # The closure list is used to track the order of cell
+        # variables and free variables in the resulting code object.
+        # The offsets used by LOAD_CLOSURE/LOAD_DEREF refer to both
+        # kinds of variables.
+        self.closure = []
         self.varnames = list(args) or []
         for i in range(len(self.varnames)):
             var = self.varnames[i]
@@ -260,6 +264,12 @@
         if flag == CO_VARARGS:
             self.argcount = self.argcount - 1
 
+    def setFreeVars(self, names):
+        self.freevars = list(names)
+
+    def setCellVars(self, names):
+        self.cellvars = names
+
     def getCode(self):
         """Get a Python code object"""
         if self.stage == RAW:
@@ -335,6 +345,7 @@
         """Convert arguments from symbolic to concrete form"""
         assert self.stage == FLAT
         self.consts.insert(0, self.docstring)
+        self.sort_cellvars()
         for i in range(len(self.insts)):
             t = self.insts[i]
             if len(t) == 2:
@@ -345,6 +356,19 @@
                     self.insts[i] = opname, conv(self, oparg)
         self.stage = CONV
 
+    def sort_cellvars(self):
+        """Sort cellvars in the order of varnames and prune from freevars.
+        """
+        cells = {}
+        for name in self.cellvars:
+            cells[name] = 1
+        self.cellvars = [name for name in self.varnames
+                         if cells.has_key(name)]
+        for name in self.cellvars:
+            del cells[name]
+        self.cellvars = self.cellvars + cells.keys()
+        self.closure = self.cellvars + self.freevars
+
     def _lookupName(self, name, list):
         """Return index of name in list, appending if necessary"""
         t = type(name)
@@ -382,6 +406,17 @@
     _convert_STORE_GLOBAL = _convert_NAME
     _convert_DELETE_GLOBAL = _convert_NAME
 
+    def _convert_DEREF(self, arg):
+        self._lookupName(arg, self.names)
+        self._lookupName(arg, self.varnames)
+        return self._lookupName(arg, self.closure)
+    _convert_LOAD_DEREF = _convert_DEREF
+    _convert_STORE_DEREF = _convert_DEREF
+
+    def _convert_LOAD_CLOSURE(self, arg):
+        self._lookupName(arg, self.varnames)
+        return self._lookupName(arg, self.closure)
+
     _cmp = list(dis.cmp_op)
     def _convert_COMPARE_OP(self, arg):
         return self._cmp.index(arg)
@@ -432,7 +467,8 @@
                         self.lnotab.getCode(), self.getConsts(),
                         tuple(self.names), tuple(self.varnames),
                         self.filename, self.name, self.lnotab.firstline,
-                        self.lnotab.getTable())
+                        self.lnotab.getTable(), tuple(self.freevars),
+                        tuple(self.cellvars))
 
     def getConsts(self):
         """Return a tuple for the const slot of the code object