|
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", "generators", "division", |
|
19 "absolute_import", "with_statement") |
|
20 |
|
21 def __init__(self): |
|
22 self.found = {} # set |
|
23 |
|
24 def visitModule(self, node): |
|
25 stmt = node.node |
|
26 for s in stmt.nodes: |
|
27 if not self.check_stmt(s): |
|
28 break |
|
29 |
|
30 def check_stmt(self, stmt): |
|
31 if is_future(stmt): |
|
32 for name, asname in stmt.names: |
|
33 if name in self.features: |
|
34 self.found[name] = 1 |
|
35 else: |
|
36 raise SyntaxError, \ |
|
37 "future feature %s is not defined" % name |
|
38 stmt.valid_future = 1 |
|
39 return 1 |
|
40 return 0 |
|
41 |
|
42 def get_features(self): |
|
43 """Return list of features enabled by future statements""" |
|
44 return self.found.keys() |
|
45 |
|
46 class BadFutureParser: |
|
47 """Check for invalid future statements""" |
|
48 |
|
49 def visitFrom(self, node): |
|
50 if hasattr(node, 'valid_future'): |
|
51 return |
|
52 if node.modname != "__future__": |
|
53 return |
|
54 raise SyntaxError, "invalid future statement " + repr(node) |
|
55 |
|
56 def find_futures(node): |
|
57 p1 = FutureParser() |
|
58 p2 = BadFutureParser() |
|
59 walk(node, p1) |
|
60 walk(node, p2) |
|
61 return p1.get_features() |
|
62 |
|
63 if __name__ == "__main__": |
|
64 import sys |
|
65 from compiler import parseFile, walk |
|
66 |
|
67 for file in sys.argv[1:]: |
|
68 print file |
|
69 tree = parseFile(file) |
|
70 v = FutureParser() |
|
71 walk(tree, v) |
|
72 print v.found |
|
73 print |