From 80e29bd1392bfae865f2ff44b1fe92a5d0fad7c8 Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Mon, 9 Apr 2001 04:28:48 +0000 Subject: Add support for future statements --- Lib/compiler/future.py | 78 ++++++++++++++++++++++++++++++++++++ Lib/compiler/pycodegen.py | 26 +++++++++--- Tools/compiler/compiler/future.py | 78 ++++++++++++++++++++++++++++++++++++ Tools/compiler/compiler/pycodegen.py | 26 +++++++++--- 4 files changed, 196 insertions(+), 12 deletions(-) create mode 100644 Lib/compiler/future.py create mode 100644 Tools/compiler/compiler/future.py 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 @@ import types 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 @@ class Module: 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 @@ class CodeGenerator: self.emit('STORE_SUBSCR') class ModuleCodeGenerator(CodeGenerator): - super_init = CodeGenerator.__init__ + __super_init = CodeGenerator.__init__ + __super_visitModule = CodeGenerator.visitModule def __init__(self, filename): # XXX is ? in compile.c self.graph = pyassem.PyFlowGraph("", 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 @@ class LocalNameFinder: 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 @@ import types 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 @@ class Module: 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 @@ class CodeGenerator: self.emit('STORE_SUBSCR') class ModuleCodeGenerator(CodeGenerator): - super_init = CodeGenerator.__init__ + __super_init = CodeGenerator.__init__ + __super_visitModule = CodeGenerator.visitModule def __init__(self, filename): # XXX is ? in compile.c self.graph = pyassem.PyFlowGraph("", 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 @@ class LocalNameFinder: 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): -- cgit v0.12