15e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis# Copyright 2007 Google, Inc. All Rights Reserved.
25e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis# Licensed to PSF under a Contributor Agreement.
35e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
45e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis"""Fixer that changes xrange(...) into range(...)."""
55e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
65e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis# Local imports
7e607823af57c176c3be23985f5bbf9260f6bd836Benjamin Petersonfrom .. import fixer_base
8e607823af57c176c3be23985f5bbf9260f6bd836Benjamin Petersonfrom ..fixer_util import Name, Call, consuming_calls
960a819d681d1004a9703b050501b70912f40b1edMartin v. Löwisfrom .. import patcomp
1060a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis
115e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
12e607823af57c176c3be23985f5bbf9260f6bd836Benjamin Petersonclass FixXrange(fixer_base.BaseFix):
13a81eae1fd71eed670d1c28bf940ea99b4bfa2335Benjamin Peterson    BM_compatible = True
145e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis    PATTERN = """
1543caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson              power<
1643caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson                 (name='range'|name='xrange') trailer< '(' args=any ')' >
1743caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson              rest=any* >
185e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis              """
195e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis
205dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson    def start_tree(self, tree, filename):
215dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson        super(FixXrange, self).start_tree(tree, filename)
225dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson        self.transformed_xranges = set()
235dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson
245dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson    def finish_tree(self, tree, filename):
255dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson        self.transformed_xranges = None
265dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson
275e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis    def transform(self, node, results):
285e37baea8007cb64b65a180e4d6c80de292a8a4aMartin v. Löwis        name = results["name"]
2984ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson        if name.value == u"xrange":
3060a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            return self.transform_xrange(node, results)
3184ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson        elif name.value == u"range":
3260a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            return self.transform_range(node, results)
3360a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis        else:
3460a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            raise ValueError(repr(name))
3560a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis
3660a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis    def transform_xrange(self, node, results):
3760a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis        name = results["name"]
386118040b7aee905bcddcb949c6815dc19ca23070Benjamin Peterson        name.replace(Name(u"range", prefix=name.prefix))
395dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson        # This prevents the new range call from being wrapped in a list later.
405dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson        self.transformed_xranges.add(id(node))
4160a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis
4260a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis    def transform_range(self, node, results):
435dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson        if (id(node) not in self.transformed_xranges and
445dfad9dc9a93ad78f56de4042ac2f3b45dd51a7bBenjamin Peterson            not self.in_special_context(node)):
4584ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson            range_call = Call(Name(u"range"), [results["args"].clone()])
4643caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson            # Encase the range call in list().
4784ad84e0bb15e7c64109e88060afdcb60ae7b740Benjamin Peterson            list_call = Call(Name(u"list"), [range_call],
486118040b7aee905bcddcb949c6815dc19ca23070Benjamin Peterson                             prefix=node.prefix)
4943caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson            # Put things that were after the range() call after the list call.
5043caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson            for n in results["rest"]:
5143caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson                list_call.append_child(n)
5243caaa09ea364aab6cbd7ede2aa9c3d004a129a5Benjamin Peterson            return list_call
5360a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis
5460a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis    P1 = "power< func=NAME trailer< '(' node=any ')' > any* >"
5560a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis    p1 = patcomp.compile_pattern(P1)
5660a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis
5760a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis    P2 = """for_stmt< 'for' any 'in' node=any ':' any* >
5860a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            | comp_for< 'for' any 'in' node=any any* >
5960a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            | comparison< any 'in' node=any any*>
6060a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis         """
6160a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis    p2 = patcomp.compile_pattern(P2)
6260a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis
6360a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis    def in_special_context(self, node):
6460a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis        if node.parent is None:
6560a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            return False
6660a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis        results = {}
6760a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis        if (node.parent.parent is not None and
6860a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis               self.p1.match(node.parent.parent, results) and
6960a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis               results["node"] is node):
7060a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            # list(d.keys()) -> list(d.keys()), etc.
7160a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis            return results["func"].value in consuming_calls
7260a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis        # for ... in d.iterkeys() -> for ... in d.keys(), etc.
7360a819d681d1004a9703b050501b70912f40b1edMartin v. Löwis        return self.p2.match(node.parent, results) and results["node"] is node
74