Skip to content

Commit 80e29bd

Browse files
committed
Add support for future statements
1 parent 42a0830 commit 80e29bd

4 files changed

Lines changed: 196 additions & 12 deletions

File tree

Lib/compiler/future.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""Parser for future statements
2+
3+
"""
4+
5+
from compiler import ast, walk
6+
7+
def is_future(stmt):
8+
"""Return true if statement is a well-formed future statement"""
9+
if not isinstance(stmt, ast.From):
10+
return 0
11+
if stmt.modname == "__future__":
12+
return 1
13+
else:
14+
return 0
15+
16+
class FutureParser:
17+
18+
features = ("nested_scopes",)
19+
20+
def __init__(self):
21+
self.found = {} # set
22+
23+
def visitModule(self, node):
24+
if node.doc is None:
25+
off = 0
26+
else:
27+
off = 1
28+
29+
stmt = node.node
30+
for s in stmt.nodes[off:]:
31+
if not self.check_stmt(s):
32+
break
33+
34+
def check_stmt(self, stmt):
35+
if is_future(stmt):
36+
for name, asname in stmt.names:
37+
if name in self.features:
38+
self.found[name] = 1
39+
else:
40+
raise SyntaxError, \
41+
"future feature %s is not defined" % name
42+
stmt.valid_future = 1
43+
return 1
44+
return 0
45+
46+
def get_features(self):
47+
"""Return list of features enabled by future statements"""
48+
return self.found.keys()
49+
50+
class BadFutureParser:
51+
"""Check for invalid future statements"""
52+
53+
def visitFrom(self, node):
54+
if hasattr(node, 'valid_future'):
55+
return
56+
if node.modname != "__future__":
57+
return
58+
raise SyntaxError, "invalid future statement"
59+
60+
def find_futures(node):
61+
p1 = FutureParser()
62+
p2 = BadFutureParser()
63+
walk(node, p1)
64+
walk(node, p2)
65+
return p1.get_features()
66+
67+
if __name__ == "__main__":
68+
import sys
69+
from compiler import parseFile, walk
70+
71+
for file in sys.argv[1:]:
72+
print file
73+
tree = parseFile(file)
74+
v = FutureParser()
75+
walk(tree, v)
76+
print v.found
77+
print
78+

Lib/compiler/pycodegen.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from cStringIO import StringIO
1010

1111
from compiler import ast, parse, walk
12-
from compiler import pyassem, misc
12+
from compiler import pyassem, misc, future
1313
from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
1414

1515
# Do we have Python 1.x or Python 2.x?
@@ -43,13 +43,13 @@ def __init__(self, source, filename):
4343
self.code = None
4444

4545
def compile(self, display=0):
46-
ast = parse(self.source)
46+
tree = parse(self.source)
4747
root, filename = os.path.split(self.filename)
4848
gen = ModuleCodeGenerator(filename)
49-
walk(ast, gen, 1)
49+
walk(tree, gen, 1)
5050
if display:
5151
import pprint
52-
print pprint.pprint(ast)
52+
print pprint.pprint(tree)
5353
self.code = gen.getCode()
5454

5555
def dump(self, f):
@@ -862,12 +862,24 @@ def visitDict(self, node):
862862
self.emit('STORE_SUBSCR')
863863

864864
class ModuleCodeGenerator(CodeGenerator):
865-
super_init = CodeGenerator.__init__
865+
__super_init = CodeGenerator.__init__
866+
__super_visitModule = CodeGenerator.visitModule
866867

867868
def __init__(self, filename):
868869
# XXX <module> is ? in compile.c
869870
self.graph = pyassem.PyFlowGraph("<module>", filename)
870-
self.super_init(filename)
871+
self.__super_init(filename)
872+
self.symbols = None
873+
self.future = None
874+
875+
def visitModule(self, node):
876+
self.future = future.find_futures(node)
877+
self.symbols = self.parseSymbols(node)
878+
self.__super_visitModule(node)
879+
880+
def parseSymbols(self, node):
881+
# XXX not implemented
882+
return None
871883

872884
class FunctionCodeGenerator(CodeGenerator):
873885
super_init = CodeGenerator.__init__
@@ -965,6 +977,8 @@ def __init__(self, names=()):
965977
for name in names:
966978
self.names.add(name)
967979

980+
# XXX list comprehensions and for loops
981+
968982
def getLocals(self):
969983
for elt in self.globals.elements():
970984
if self.names.has_elt(elt):

Tools/compiler/compiler/future.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""Parser for future statements
2+
3+
"""
4+
5+
from compiler import ast, walk
6+
7+
def is_future(stmt):
8+
"""Return true if statement is a well-formed future statement"""
9+
if not isinstance(stmt, ast.From):
10+
return 0
11+
if stmt.modname == "__future__":
12+
return 1
13+
else:
14+
return 0
15+
16+
class FutureParser:
17+
18+
features = ("nested_scopes",)
19+
20+
def __init__(self):
21+
self.found = {} # set
22+
23+
def visitModule(self, node):
24+
if node.doc is None:
25+
off = 0
26+
else:
27+
off = 1
28+
29+
stmt = node.node
30+
for s in stmt.nodes[off:]:
31+
if not self.check_stmt(s):
32+
break
33+
34+
def check_stmt(self, stmt):
35+
if is_future(stmt):
36+
for name, asname in stmt.names:
37+
if name in self.features:
38+
self.found[name] = 1
39+
else:
40+
raise SyntaxError, \
41+
"future feature %s is not defined" % name
42+
stmt.valid_future = 1
43+
return 1
44+
return 0
45+
46+
def get_features(self):
47+
"""Return list of features enabled by future statements"""
48+
return self.found.keys()
49+
50+
class BadFutureParser:
51+
"""Check for invalid future statements"""
52+
53+
def visitFrom(self, node):
54+
if hasattr(node, 'valid_future'):
55+
return
56+
if node.modname != "__future__":
57+
return
58+
raise SyntaxError, "invalid future statement"
59+
60+
def find_futures(node):
61+
p1 = FutureParser()
62+
p2 = BadFutureParser()
63+
walk(node, p1)
64+
walk(node, p2)
65+
return p1.get_features()
66+
67+
if __name__ == "__main__":
68+
import sys
69+
from compiler import parseFile, walk
70+
71+
for file in sys.argv[1:]:
72+
print file
73+
tree = parseFile(file)
74+
v = FutureParser()
75+
walk(tree, v)
76+
print v.found
77+
print
78+

Tools/compiler/compiler/pycodegen.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from cStringIO import StringIO
1010

1111
from compiler import ast, parse, walk
12-
from compiler import pyassem, misc
12+
from compiler import pyassem, misc, future
1313
from compiler.pyassem import CO_VARARGS, CO_VARKEYWORDS, CO_NEWLOCALS, TupleArg
1414

1515
# Do we have Python 1.x or Python 2.x?
@@ -43,13 +43,13 @@ def __init__(self, source, filename):
4343
self.code = None
4444

4545
def compile(self, display=0):
46-
ast = parse(self.source)
46+
tree = parse(self.source)
4747
root, filename = os.path.split(self.filename)
4848
gen = ModuleCodeGenerator(filename)
49-
walk(ast, gen, 1)
49+
walk(tree, gen, 1)
5050
if display:
5151
import pprint
52-
print pprint.pprint(ast)
52+
print pprint.pprint(tree)
5353
self.code = gen.getCode()
5454

5555
def dump(self, f):
@@ -862,12 +862,24 @@ def visitDict(self, node):
862862
self.emit('STORE_SUBSCR')
863863

864864
class ModuleCodeGenerator(CodeGenerator):
865-
super_init = CodeGenerator.__init__
865+
__super_init = CodeGenerator.__init__
866+
__super_visitModule = CodeGenerator.visitModule
866867

867868
def __init__(self, filename):
868869
# XXX <module> is ? in compile.c
869870
self.graph = pyassem.PyFlowGraph("<module>", filename)
870-
self.super_init(filename)
871+
self.__super_init(filename)
872+
self.symbols = None
873+
self.future = None
874+
875+
def visitModule(self, node):
876+
self.future = future.find_futures(node)
877+
self.symbols = self.parseSymbols(node)
878+
self.__super_visitModule(node)
879+
880+
def parseSymbols(self, node):
881+
# XXX not implemented
882+
return None
871883

872884
class FunctionCodeGenerator(CodeGenerator):
873885
super_init = CodeGenerator.__init__
@@ -965,6 +977,8 @@ def __init__(self, names=()):
965977
for name in names:
966978
self.names.add(name)
967979

980+
# XXX list comprehensions and for loops
981+
968982
def getLocals(self):
969983
for elt in self.globals.elements():
970984
if self.names.has_elt(elt):

0 commit comments

Comments
 (0)