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):