Add support for future statements
This commit is contained in:
parent
42a0830713
commit
80e29bd139
78
Lib/compiler/future.py
Normal file
78
Lib/compiler/future.py
Normal 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
|
||||||
|
|
@ -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):
|
||||||
|
78
Tools/compiler/compiler/future.py
Normal file
78
Tools/compiler/compiler/future.py
Normal 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
|
||||||
|
|
@ -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):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user