Add support for future statements

This commit is contained in:
Jeremy Hylton 2001-04-09 04:28:48 +00:00
parent 42a0830713
commit 80e29bd139
4 changed files with 196 additions and 12 deletions

78
Lib/compiler/future.py Normal file
View File

@ -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

View File

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

View File

@ -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

View File

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