Add support for future statements
diff --git a/Lib/compiler/future.py b/Lib/compiler/future.py
new file mode 100644
index 0000000..fe25b72
--- /dev/null
+++ b/Lib/compiler/future.py
@@ -0,0 +1,78 @@
+"""Parser for future statements
+
+"""
+
+from compiler import ast, walk
+
+def is_future(stmt):
+    """Return true if statement is a well-formed future statement"""
+    if not isinstance(stmt, ast.From):
+        return 0
+    if stmt.modname == "__future__":
+        return 1
+    else:
+        return 0
+
+class FutureParser:
+
+    features = ("nested_scopes",)
+    
+    def __init__(self):
+        self.found = {} # set
+
+    def visitModule(self, node):
+        if node.doc is None:
+            off = 0
+        else:
+            off = 1
+
+        stmt = node.node
+        for s in stmt.nodes[off:]:
+            if not self.check_stmt(s):
+                break
+
+    def check_stmt(self, stmt):
+        if is_future(stmt):
+            for name, asname in stmt.names:
+                if name in self.features:
+                    self.found[name] = 1
+                else:
+                    raise SyntaxError, \
+                          "future feature %s is not defined" % name
+            stmt.valid_future = 1
+            return 1
+        return 0
+
+    def get_features(self):
+        """Return list of features enabled by future statements"""
+        return self.found.keys()
+
+class BadFutureParser:
+    """Check for invalid future statements"""
+
+    def visitFrom(self, node):
+        if hasattr(node, 'valid_future'):
+            return
+        if node.modname != "__future__":
+            return
+        raise SyntaxError, "invalid future statement"
+
+def find_futures(node):
+    p1 = FutureParser()
+    p2 = BadFutureParser()
+    walk(node, p1)
+    walk(node, p2)
+    return p1.get_features()
+
+if __name__ == "__main__":
+    import sys
+    from compiler import parseFile, walk
+
+    for file in sys.argv[1:]:
+        print file
+        tree = parseFile(file)
+        v = FutureParser()
+        walk(tree, v)
+        print v.found
+        print
+
diff --git a/Lib/compiler/pycodegen.py b/Lib/compiler/pycodegen.py
index a1b5d1d..e6849e5 100644
--- a/Lib/compiler/pycodegen.py
+++ b/Lib/compiler/pycodegen.py
@@ -9,7 +9,7 @@
 from cStringIO import StringIO
 
 from compiler import ast, parse, walk
-from compiler import pyassem, misc
+from compiler import pyassem, misc, future
 from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
 
 # Do we have Python 1.x or Python 2.x?
@@ -43,13 +43,13 @@
         self.code = None
 
     def compile(self, display=0):
-        ast = parse(self.source)
+        tree = parse(self.source)
         root, filename = os.path.split(self.filename)
         gen = ModuleCodeGenerator(filename)
-        walk(ast, gen, 1)
+        walk(tree, gen, 1)
         if display:
             import pprint
-            print pprint.pprint(ast)
+            print pprint.pprint(tree)
         self.code = gen.getCode()
 
     def dump(self, f):
@@ -862,12 +862,24 @@
             self.emit('STORE_SUBSCR')
 
 class ModuleCodeGenerator(CodeGenerator):
-    super_init = CodeGenerator.__init__
+    __super_init = CodeGenerator.__init__
+    __super_visitModule = CodeGenerator.visitModule
     
     def __init__(self, filename):
         # XXX <module> is ? in compile.c
         self.graph = pyassem.PyFlowGraph("<module>", filename)
-        self.super_init(filename)
+        self.__super_init(filename)
+        self.symbols = None
+        self.future = None
+
+    def visitModule(self, node):
+        self.future = future.find_futures(node)
+        self.symbols = self.parseSymbols(node)
+        self.__super_visitModule(node)
+
+    def parseSymbols(self, node):
+        # XXX not implemented
+        return None
 
 class FunctionCodeGenerator(CodeGenerator):
     super_init = CodeGenerator.__init__
@@ -965,6 +977,8 @@
         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):
diff --git a/Tools/compiler/compiler/future.py b/Tools/compiler/compiler/future.py
new file mode 100644
index 0000000..fe25b72
--- /dev/null
+++ b/Tools/compiler/compiler/future.py
@@ -0,0 +1,78 @@
+"""Parser for future statements
+
+"""
+
+from compiler import ast, walk
+
+def is_future(stmt):
+    """Return true if statement is a well-formed future statement"""
+    if not isinstance(stmt, ast.From):
+        return 0
+    if stmt.modname == "__future__":
+        return 1
+    else:
+        return 0
+
+class FutureParser:
+
+    features = ("nested_scopes",)
+    
+    def __init__(self):
+        self.found = {} # set
+
+    def visitModule(self, node):
+        if node.doc is None:
+            off = 0
+        else:
+            off = 1
+
+        stmt = node.node
+        for s in stmt.nodes[off:]:
+            if not self.check_stmt(s):
+                break
+
+    def check_stmt(self, stmt):
+        if is_future(stmt):
+            for name, asname in stmt.names:
+                if name in self.features:
+                    self.found[name] = 1
+                else:
+                    raise SyntaxError, \
+                          "future feature %s is not defined" % name
+            stmt.valid_future = 1
+            return 1
+        return 0
+
+    def get_features(self):
+        """Return list of features enabled by future statements"""
+        return self.found.keys()
+
+class BadFutureParser:
+    """Check for invalid future statements"""
+
+    def visitFrom(self, node):
+        if hasattr(node, 'valid_future'):
+            return
+        if node.modname != "__future__":
+            return
+        raise SyntaxError, "invalid future statement"
+
+def find_futures(node):
+    p1 = FutureParser()
+    p2 = BadFutureParser()
+    walk(node, p1)
+    walk(node, p2)
+    return p1.get_features()
+
+if __name__ == "__main__":
+    import sys
+    from compiler import parseFile, walk
+
+    for file in sys.argv[1:]:
+        print file
+        tree = parseFile(file)
+        v = FutureParser()
+        walk(tree, v)
+        print v.found
+        print
+
diff --git a/Tools/compiler/compiler/pycodegen.py b/Tools/compiler/compiler/pycodegen.py
index a1b5d1d..e6849e5 100644
--- a/Tools/compiler/compiler/pycodegen.py
+++ b/Tools/compiler/compiler/pycodegen.py
@@ -9,7 +9,7 @@
 from cStringIO import StringIO
 
 from compiler import ast, parse, walk
-from compiler import pyassem, misc
+from compiler import pyassem, misc, future
 from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
 
 # Do we have Python 1.x or Python 2.x?
@@ -43,13 +43,13 @@
         self.code = None
 
     def compile(self, display=0):
-        ast = parse(self.source)
+        tree = parse(self.source)
         root, filename = os.path.split(self.filename)
         gen = ModuleCodeGenerator(filename)
-        walk(ast, gen, 1)
+        walk(tree, gen, 1)
         if display:
             import pprint
-            print pprint.pprint(ast)
+            print pprint.pprint(tree)
         self.code = gen.getCode()
 
     def dump(self, f):
@@ -862,12 +862,24 @@
             self.emit('STORE_SUBSCR')
 
 class ModuleCodeGenerator(CodeGenerator):
-    super_init = CodeGenerator.__init__
+    __super_init = CodeGenerator.__init__
+    __super_visitModule = CodeGenerator.visitModule
     
     def __init__(self, filename):
         # XXX <module> is ? in compile.c
         self.graph = pyassem.PyFlowGraph("<module>", filename)
-        self.super_init(filename)
+        self.__super_init(filename)
+        self.symbols = None
+        self.future = None
+
+    def visitModule(self, node):
+        self.future = future.find_futures(node)
+        self.symbols = self.parseSymbols(node)
+        self.__super_visitModule(node)
+
+    def parseSymbols(self, node):
+        # XXX not implemented
+        return None
 
 class FunctionCodeGenerator(CodeGenerator):
     super_init = CodeGenerator.__init__
@@ -965,6 +977,8 @@
         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):