Commit 7818d696 authored by Jeremy Hylton's avatar Jeremy Hylton

Add support for future statements

parent c9656e8b
"""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
...@@ -9,7 +9,7 @@ import types ...@@ -9,7 +9,7 @@ import types
from cStringIO import StringIO from cStringIO import StringIO
from compiler import ast, parse, walk 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 from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
# Do we have Python 1.x or Python 2.x? # Do we have Python 1.x or Python 2.x?
...@@ -43,13 +43,13 @@ class Module: ...@@ -43,13 +43,13 @@ class Module:
self.code = None self.code = None
def compile(self, display=0): def compile(self, display=0):
ast = parse(self.source) tree = parse(self.source)
root, filename = os.path.split(self.filename) root, filename = os.path.split(self.filename)
gen = ModuleCodeGenerator(filename) gen = ModuleCodeGenerator(filename)
walk(ast, gen, 1) walk(tree, gen, 1)
if display: if display:
import pprint import pprint
print pprint.pprint(ast) print pprint.pprint(tree)
self.code = gen.getCode() self.code = gen.getCode()
def dump(self, f): def dump(self, f):
...@@ -862,12 +862,24 @@ class CodeGenerator: ...@@ -862,12 +862,24 @@ class CodeGenerator:
self.emit('STORE_SUBSCR') self.emit('STORE_SUBSCR')
class ModuleCodeGenerator(CodeGenerator): class ModuleCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__ __super_init = CodeGenerator.__init__
__super_visitModule = CodeGenerator.visitModule
def __init__(self, filename): def __init__(self, filename):
# XXX <module> is ? in compile.c # XXX <module> is ? in compile.c
self.graph = pyassem.PyFlowGraph("<module>", filename) 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): class FunctionCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__ super_init = CodeGenerator.__init__
...@@ -965,6 +977,8 @@ class LocalNameFinder: ...@@ -965,6 +977,8 @@ class LocalNameFinder:
for name in names: for name in names:
self.names.add(name) self.names.add(name)
# XXX list comprehensions and for loops
def getLocals(self): def getLocals(self):
for elt in self.globals.elements(): for elt in self.globals.elements():
if self.names.has_elt(elt): if self.names.has_elt(elt):
......
"""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
...@@ -9,7 +9,7 @@ import types ...@@ -9,7 +9,7 @@ import types
from cStringIO import StringIO from cStringIO import StringIO
from compiler import ast, parse, walk 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 from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
# Do we have Python 1.x or Python 2.x? # Do we have Python 1.x or Python 2.x?
...@@ -43,13 +43,13 @@ class Module: ...@@ -43,13 +43,13 @@ class Module:
self.code = None self.code = None
def compile(self, display=0): def compile(self, display=0):
ast = parse(self.source) tree = parse(self.source)
root, filename = os.path.split(self.filename) root, filename = os.path.split(self.filename)
gen = ModuleCodeGenerator(filename) gen = ModuleCodeGenerator(filename)
walk(ast, gen, 1) walk(tree, gen, 1)
if display: if display:
import pprint import pprint
print pprint.pprint(ast) print pprint.pprint(tree)
self.code = gen.getCode() self.code = gen.getCode()
def dump(self, f): def dump(self, f):
...@@ -862,12 +862,24 @@ class CodeGenerator: ...@@ -862,12 +862,24 @@ class CodeGenerator:
self.emit('STORE_SUBSCR') self.emit('STORE_SUBSCR')
class ModuleCodeGenerator(CodeGenerator): class ModuleCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__ __super_init = CodeGenerator.__init__
__super_visitModule = CodeGenerator.visitModule
def __init__(self, filename): def __init__(self, filename):
# XXX <module> is ? in compile.c # XXX <module> is ? in compile.c
self.graph = pyassem.PyFlowGraph("<module>", filename) 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): class FunctionCodeGenerator(CodeGenerator):
super_init = CodeGenerator.__init__ super_init = CodeGenerator.__init__
...@@ -965,6 +977,8 @@ class LocalNameFinder: ...@@ -965,6 +977,8 @@ class LocalNameFinder:
for name in names: for name in names:
self.names.add(name) self.names.add(name)
# XXX list comprehensions and for loops
def getLocals(self): def getLocals(self):
for elt in self.globals.elements(): for elt in self.globals.elements():
if self.names.has_elt(elt): if self.names.has_elt(elt):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment