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