17db96d56Sopenharmony_ci# Copyright 2006 Google, Inc. All Rights Reserved.
27db96d56Sopenharmony_ci# Licensed to PSF under a Contributor Agreement.
37db96d56Sopenharmony_ci
47db96d56Sopenharmony_ci"""Fixer for apply().
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ciThis converts apply(func, v, k) into (func)(*v, **k)."""
77db96d56Sopenharmony_ci
87db96d56Sopenharmony_ci# Local imports
97db96d56Sopenharmony_cifrom .. import pytree
107db96d56Sopenharmony_cifrom ..pgen2 import token
117db96d56Sopenharmony_cifrom .. import fixer_base
127db96d56Sopenharmony_cifrom ..fixer_util import Call, Comma, parenthesize
137db96d56Sopenharmony_ci
147db96d56Sopenharmony_ciclass FixApply(fixer_base.BaseFix):
157db96d56Sopenharmony_ci    BM_compatible = True
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ci    PATTERN = """
187db96d56Sopenharmony_ci    power< 'apply'
197db96d56Sopenharmony_ci        trailer<
207db96d56Sopenharmony_ci            '('
217db96d56Sopenharmony_ci            arglist<
227db96d56Sopenharmony_ci                (not argument<NAME '=' any>) func=any ','
237db96d56Sopenharmony_ci                (not argument<NAME '=' any>) args=any [','
247db96d56Sopenharmony_ci                (not argument<NAME '=' any>) kwds=any] [',']
257db96d56Sopenharmony_ci            >
267db96d56Sopenharmony_ci            ')'
277db96d56Sopenharmony_ci        >
287db96d56Sopenharmony_ci    >
297db96d56Sopenharmony_ci    """
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ci    def transform(self, node, results):
327db96d56Sopenharmony_ci        syms = self.syms
337db96d56Sopenharmony_ci        assert results
347db96d56Sopenharmony_ci        func = results["func"]
357db96d56Sopenharmony_ci        args = results["args"]
367db96d56Sopenharmony_ci        kwds = results.get("kwds")
377db96d56Sopenharmony_ci        # I feel like we should be able to express this logic in the
387db96d56Sopenharmony_ci        # PATTERN above but I don't know how to do it so...
397db96d56Sopenharmony_ci        if args:
407db96d56Sopenharmony_ci            if (args.type == self.syms.argument and
417db96d56Sopenharmony_ci                args.children[0].value in {'**', '*'}):
427db96d56Sopenharmony_ci                return  # Make no change.
437db96d56Sopenharmony_ci        if kwds and (kwds.type == self.syms.argument and
447db96d56Sopenharmony_ci                     kwds.children[0].value == '**'):
457db96d56Sopenharmony_ci            return  # Make no change.
467db96d56Sopenharmony_ci        prefix = node.prefix
477db96d56Sopenharmony_ci        func = func.clone()
487db96d56Sopenharmony_ci        if (func.type not in (token.NAME, syms.atom) and
497db96d56Sopenharmony_ci            (func.type != syms.power or
507db96d56Sopenharmony_ci             func.children[-2].type == token.DOUBLESTAR)):
517db96d56Sopenharmony_ci            # Need to parenthesize
527db96d56Sopenharmony_ci            func = parenthesize(func)
537db96d56Sopenharmony_ci        func.prefix = ""
547db96d56Sopenharmony_ci        args = args.clone()
557db96d56Sopenharmony_ci        args.prefix = ""
567db96d56Sopenharmony_ci        if kwds is not None:
577db96d56Sopenharmony_ci            kwds = kwds.clone()
587db96d56Sopenharmony_ci            kwds.prefix = ""
597db96d56Sopenharmony_ci        l_newargs = [pytree.Leaf(token.STAR, "*"), args]
607db96d56Sopenharmony_ci        if kwds is not None:
617db96d56Sopenharmony_ci            l_newargs.extend([Comma(),
627db96d56Sopenharmony_ci                              pytree.Leaf(token.DOUBLESTAR, "**"),
637db96d56Sopenharmony_ci                              kwds])
647db96d56Sopenharmony_ci            l_newargs[-2].prefix = " " # that's the ** token
657db96d56Sopenharmony_ci        # XXX Sometimes we could be cleverer, e.g. apply(f, (x, y) + t)
667db96d56Sopenharmony_ci        # can be translated into f(x, y, *t) instead of f(*(x, y) + t)
677db96d56Sopenharmony_ci        #new = pytree.Node(syms.power, (func, ArgList(l_newargs)))
687db96d56Sopenharmony_ci        return Call(func, l_newargs, prefix=prefix)
69