180e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton"""Parser for future statements
280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton"""
480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
580e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hyltonfrom compiler import ast, walk
680e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
780e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hyltondef is_future(stmt):
880e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    """Return true if statement is a well-formed future statement"""
980e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    if not isinstance(stmt, ast.From):
1080e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        return 0
1180e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    if stmt.modname == "__future__":
1280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        return 1
1380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    else:
1480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        return 0
1580e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
1680e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hyltonclass FutureParser:
1780e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
1834aa7ba11431a46e72ec30ee7528f2e52adbed7fThomas Wouters    features = ("nested_scopes", "generators", "division",
19311d071541ba1fd8615ecf604026e96d547c1d80Neal Norwitz                "absolute_import", "with_statement", "print_function",
20311d071541ba1fd8615ecf604026e96d547c1d80Neal Norwitz                "unicode_literals")
21e0c446bb4ad67294f42d4cb53b4ff28413bd8ddeTim Peters
2280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    def __init__(self):
2380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        self.found = {} # set
2480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
2580e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    def visitModule(self, node):
2680e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        stmt = node.node
27ec5bfd13cada33ed36f93fd76b1355ce9ee2710fJeremy Hylton        for s in stmt.nodes:
2880e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton            if not self.check_stmt(s):
2980e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton                break
3080e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
3180e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    def check_stmt(self, stmt):
3280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        if is_future(stmt):
3380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton            for name, asname in stmt.names:
3480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton                if name in self.features:
3580e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton                    self.found[name] = 1
3680e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton                else:
3780e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton                    raise SyntaxError, \
3880e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton                          "future feature %s is not defined" % name
3980e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton            stmt.valid_future = 1
4080e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton            return 1
4180e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        return 0
4280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
4380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    def get_features(self):
4480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        """Return list of features enabled by future statements"""
4580e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        return self.found.keys()
4680e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
4780e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hyltonclass BadFutureParser:
4880e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    """Check for invalid future statements"""
4980e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
5080e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    def visitFrom(self, node):
5180e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        if hasattr(node, 'valid_future'):
5280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton            return
5380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        if node.modname != "__future__":
5480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton            return
55415ed937c21f0d563fb11a20189831b908673462Martin v. Löwis        raise SyntaxError, "invalid future statement " + repr(node)
5680e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
5780e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hyltondef find_futures(node):
5880e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    p1 = FutureParser()
5980e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    p2 = BadFutureParser()
6080e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    walk(node, p1)
6180e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    walk(node, p2)
6280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    return p1.get_features()
6380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
6480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hyltonif __name__ == "__main__":
6580e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    import sys
6680e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    from compiler import parseFile, walk
6780e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton
6880e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton    for file in sys.argv[1:]:
6980e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        print file
7080e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        tree = parseFile(file)
7180e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        v = FutureParser()
7280e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        walk(tree, v)
7380e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        print v.found
7480e29bd1392bfae865f2ff44b1fe92a5d0fad7c8Jeremy Hylton        print
75