17db96d56Sopenharmony_ci"""Fixer for 'raise E, V, T'
27db96d56Sopenharmony_ci
37db96d56Sopenharmony_ciraise         -> raise
47db96d56Sopenharmony_ciraise E       -> raise E
57db96d56Sopenharmony_ciraise E, V    -> raise E(V)
67db96d56Sopenharmony_ciraise E, V, T -> raise E(V).with_traceback(T)
77db96d56Sopenharmony_ciraise E, None, T -> raise E.with_traceback(T)
87db96d56Sopenharmony_ci
97db96d56Sopenharmony_ciraise (((E, E'), E''), E'''), V -> raise E(V)
107db96d56Sopenharmony_ciraise "foo", V, T               -> warns about string exceptions
117db96d56Sopenharmony_ci
127db96d56Sopenharmony_ci
137db96d56Sopenharmony_ciCAVEATS:
147db96d56Sopenharmony_ci1) "raise E, V" will be incorrectly translated if V is an exception
157db96d56Sopenharmony_ci   instance. The correct Python 3 idiom is
167db96d56Sopenharmony_ci
177db96d56Sopenharmony_ci        raise E from V
187db96d56Sopenharmony_ci
197db96d56Sopenharmony_ci   but since we can't detect instance-hood by syntax alone and since
207db96d56Sopenharmony_ci   any client code would have to be changed as well, we don't automate
217db96d56Sopenharmony_ci   this.
227db96d56Sopenharmony_ci"""
237db96d56Sopenharmony_ci# Author: Collin Winter
247db96d56Sopenharmony_ci
257db96d56Sopenharmony_ci# Local imports
267db96d56Sopenharmony_cifrom .. import pytree
277db96d56Sopenharmony_cifrom ..pgen2 import token
287db96d56Sopenharmony_cifrom .. import fixer_base
297db96d56Sopenharmony_cifrom ..fixer_util import Name, Call, Attr, ArgList, is_tuple
307db96d56Sopenharmony_ci
317db96d56Sopenharmony_ciclass FixRaise(fixer_base.BaseFix):
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_ci    BM_compatible = True
347db96d56Sopenharmony_ci    PATTERN = """
357db96d56Sopenharmony_ci    raise_stmt< 'raise' exc=any [',' val=any [',' tb=any]] >
367db96d56Sopenharmony_ci    """
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci    def transform(self, node, results):
397db96d56Sopenharmony_ci        syms = self.syms
407db96d56Sopenharmony_ci
417db96d56Sopenharmony_ci        exc = results["exc"].clone()
427db96d56Sopenharmony_ci        if exc.type == token.STRING:
437db96d56Sopenharmony_ci            msg = "Python 3 does not support string exceptions"
447db96d56Sopenharmony_ci            self.cannot_convert(node, msg)
457db96d56Sopenharmony_ci            return
467db96d56Sopenharmony_ci
477db96d56Sopenharmony_ci        # Python 2 supports
487db96d56Sopenharmony_ci        #  raise ((((E1, E2), E3), E4), E5), V
497db96d56Sopenharmony_ci        # as a synonym for
507db96d56Sopenharmony_ci        #  raise E1, V
517db96d56Sopenharmony_ci        # Since Python 3 will not support this, we recurse down any tuple
527db96d56Sopenharmony_ci        # literals, always taking the first element.
537db96d56Sopenharmony_ci        if is_tuple(exc):
547db96d56Sopenharmony_ci            while is_tuple(exc):
557db96d56Sopenharmony_ci                # exc.children[1:-1] is the unparenthesized tuple
567db96d56Sopenharmony_ci                # exc.children[1].children[0] is the first element of the tuple
577db96d56Sopenharmony_ci                exc = exc.children[1].children[0].clone()
587db96d56Sopenharmony_ci            exc.prefix = " "
597db96d56Sopenharmony_ci
607db96d56Sopenharmony_ci        if "val" not in results:
617db96d56Sopenharmony_ci            # One-argument raise
627db96d56Sopenharmony_ci            new = pytree.Node(syms.raise_stmt, [Name("raise"), exc])
637db96d56Sopenharmony_ci            new.prefix = node.prefix
647db96d56Sopenharmony_ci            return new
657db96d56Sopenharmony_ci
667db96d56Sopenharmony_ci        val = results["val"].clone()
677db96d56Sopenharmony_ci        if is_tuple(val):
687db96d56Sopenharmony_ci            args = [c.clone() for c in val.children[1:-1]]
697db96d56Sopenharmony_ci        else:
707db96d56Sopenharmony_ci            val.prefix = ""
717db96d56Sopenharmony_ci            args = [val]
727db96d56Sopenharmony_ci
737db96d56Sopenharmony_ci        if "tb" in results:
747db96d56Sopenharmony_ci            tb = results["tb"].clone()
757db96d56Sopenharmony_ci            tb.prefix = ""
767db96d56Sopenharmony_ci
777db96d56Sopenharmony_ci            e = exc
787db96d56Sopenharmony_ci            # If there's a traceback and None is passed as the value, then don't
797db96d56Sopenharmony_ci            # add a call, since the user probably just wants to add a
807db96d56Sopenharmony_ci            # traceback. See issue #9661.
817db96d56Sopenharmony_ci            if val.type != token.NAME or val.value != "None":
827db96d56Sopenharmony_ci                e = Call(exc, args)
837db96d56Sopenharmony_ci            with_tb = Attr(e, Name('with_traceback')) + [ArgList([tb])]
847db96d56Sopenharmony_ci            new = pytree.Node(syms.simple_stmt, [Name("raise")] + with_tb)
857db96d56Sopenharmony_ci            new.prefix = node.prefix
867db96d56Sopenharmony_ci            return new
877db96d56Sopenharmony_ci        else:
887db96d56Sopenharmony_ci            return pytree.Node(syms.raise_stmt,
897db96d56Sopenharmony_ci                               [Name("raise"), Call(exc, args)],
907db96d56Sopenharmony_ci                               prefix=node.prefix)
91