xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/ast.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker"""
2*cda5da8dSAndroid Build Coastguard Worker    ast
3*cda5da8dSAndroid Build Coastguard Worker    ~~~
4*cda5da8dSAndroid Build Coastguard Worker
5*cda5da8dSAndroid Build Coastguard Worker    The `ast` module helps Python applications to process trees of the Python
6*cda5da8dSAndroid Build Coastguard Worker    abstract syntax grammar.  The abstract syntax itself might change with
7*cda5da8dSAndroid Build Coastguard Worker    each Python release; this module helps to find out programmatically what
8*cda5da8dSAndroid Build Coastguard Worker    the current grammar looks like and allows modifications of it.
9*cda5da8dSAndroid Build Coastguard Worker
10*cda5da8dSAndroid Build Coastguard Worker    An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
11*cda5da8dSAndroid Build Coastguard Worker    a flag to the `compile()` builtin function or by using the `parse()`
12*cda5da8dSAndroid Build Coastguard Worker    function from this module.  The result will be a tree of objects whose
13*cda5da8dSAndroid Build Coastguard Worker    classes all inherit from `ast.AST`.
14*cda5da8dSAndroid Build Coastguard Worker
15*cda5da8dSAndroid Build Coastguard Worker    A modified abstract syntax tree can be compiled into a Python code object
16*cda5da8dSAndroid Build Coastguard Worker    using the built-in `compile()` function.
17*cda5da8dSAndroid Build Coastguard Worker
18*cda5da8dSAndroid Build Coastguard Worker    Additionally various helper functions are provided that make working with
19*cda5da8dSAndroid Build Coastguard Worker    the trees simpler.  The main intention of the helper functions and this
20*cda5da8dSAndroid Build Coastguard Worker    module in general is to provide an easy to use interface for libraries
21*cda5da8dSAndroid Build Coastguard Worker    that work tightly with the python syntax (template engines for example).
22*cda5da8dSAndroid Build Coastguard Worker
23*cda5da8dSAndroid Build Coastguard Worker
24*cda5da8dSAndroid Build Coastguard Worker    :copyright: Copyright 2008 by Armin Ronacher.
25*cda5da8dSAndroid Build Coastguard Worker    :license: Python License.
26*cda5da8dSAndroid Build Coastguard Worker"""
27*cda5da8dSAndroid Build Coastguard Workerimport sys
28*cda5da8dSAndroid Build Coastguard Workerfrom _ast import *
29*cda5da8dSAndroid Build Coastguard Workerfrom contextlib import contextmanager, nullcontext
30*cda5da8dSAndroid Build Coastguard Workerfrom enum import IntEnum, auto, _simple_enum
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker
33*cda5da8dSAndroid Build Coastguard Workerdef parse(source, filename='<unknown>', mode='exec', *,
34*cda5da8dSAndroid Build Coastguard Worker          type_comments=False, feature_version=None):
35*cda5da8dSAndroid Build Coastguard Worker    """
36*cda5da8dSAndroid Build Coastguard Worker    Parse the source into an AST node.
37*cda5da8dSAndroid Build Coastguard Worker    Equivalent to compile(source, filename, mode, PyCF_ONLY_AST).
38*cda5da8dSAndroid Build Coastguard Worker    Pass type_comments=True to get back type comments where the syntax allows.
39*cda5da8dSAndroid Build Coastguard Worker    """
40*cda5da8dSAndroid Build Coastguard Worker    flags = PyCF_ONLY_AST
41*cda5da8dSAndroid Build Coastguard Worker    if type_comments:
42*cda5da8dSAndroid Build Coastguard Worker        flags |= PyCF_TYPE_COMMENTS
43*cda5da8dSAndroid Build Coastguard Worker    if isinstance(feature_version, tuple):
44*cda5da8dSAndroid Build Coastguard Worker        major, minor = feature_version  # Should be a 2-tuple.
45*cda5da8dSAndroid Build Coastguard Worker        assert major == 3
46*cda5da8dSAndroid Build Coastguard Worker        feature_version = minor
47*cda5da8dSAndroid Build Coastguard Worker    elif feature_version is None:
48*cda5da8dSAndroid Build Coastguard Worker        feature_version = -1
49*cda5da8dSAndroid Build Coastguard Worker    # Else it should be an int giving the minor version for 3.x.
50*cda5da8dSAndroid Build Coastguard Worker    return compile(source, filename, mode, flags,
51*cda5da8dSAndroid Build Coastguard Worker                   _feature_version=feature_version)
52*cda5da8dSAndroid Build Coastguard Worker
53*cda5da8dSAndroid Build Coastguard Worker
54*cda5da8dSAndroid Build Coastguard Workerdef literal_eval(node_or_string):
55*cda5da8dSAndroid Build Coastguard Worker    """
56*cda5da8dSAndroid Build Coastguard Worker    Evaluate an expression node or a string containing only a Python
57*cda5da8dSAndroid Build Coastguard Worker    expression.  The string or node provided may only consist of the following
58*cda5da8dSAndroid Build Coastguard Worker    Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
59*cda5da8dSAndroid Build Coastguard Worker    sets, booleans, and None.
60*cda5da8dSAndroid Build Coastguard Worker
61*cda5da8dSAndroid Build Coastguard Worker    Caution: A complex expression can overflow the C stack and cause a crash.
62*cda5da8dSAndroid Build Coastguard Worker    """
63*cda5da8dSAndroid Build Coastguard Worker    if isinstance(node_or_string, str):
64*cda5da8dSAndroid Build Coastguard Worker        node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval')
65*cda5da8dSAndroid Build Coastguard Worker    if isinstance(node_or_string, Expression):
66*cda5da8dSAndroid Build Coastguard Worker        node_or_string = node_or_string.body
67*cda5da8dSAndroid Build Coastguard Worker    def _raise_malformed_node(node):
68*cda5da8dSAndroid Build Coastguard Worker        msg = "malformed node or string"
69*cda5da8dSAndroid Build Coastguard Worker        if lno := getattr(node, 'lineno', None):
70*cda5da8dSAndroid Build Coastguard Worker            msg += f' on line {lno}'
71*cda5da8dSAndroid Build Coastguard Worker        raise ValueError(msg + f': {node!r}')
72*cda5da8dSAndroid Build Coastguard Worker    def _convert_num(node):
73*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
74*cda5da8dSAndroid Build Coastguard Worker            _raise_malformed_node(node)
75*cda5da8dSAndroid Build Coastguard Worker        return node.value
76*cda5da8dSAndroid Build Coastguard Worker    def _convert_signed_num(node):
77*cda5da8dSAndroid Build Coastguard Worker        if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
78*cda5da8dSAndroid Build Coastguard Worker            operand = _convert_num(node.operand)
79*cda5da8dSAndroid Build Coastguard Worker            if isinstance(node.op, UAdd):
80*cda5da8dSAndroid Build Coastguard Worker                return + operand
81*cda5da8dSAndroid Build Coastguard Worker            else:
82*cda5da8dSAndroid Build Coastguard Worker                return - operand
83*cda5da8dSAndroid Build Coastguard Worker        return _convert_num(node)
84*cda5da8dSAndroid Build Coastguard Worker    def _convert(node):
85*cda5da8dSAndroid Build Coastguard Worker        if isinstance(node, Constant):
86*cda5da8dSAndroid Build Coastguard Worker            return node.value
87*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, Tuple):
88*cda5da8dSAndroid Build Coastguard Worker            return tuple(map(_convert, node.elts))
89*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, List):
90*cda5da8dSAndroid Build Coastguard Worker            return list(map(_convert, node.elts))
91*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, Set):
92*cda5da8dSAndroid Build Coastguard Worker            return set(map(_convert, node.elts))
93*cda5da8dSAndroid Build Coastguard Worker        elif (isinstance(node, Call) and isinstance(node.func, Name) and
94*cda5da8dSAndroid Build Coastguard Worker              node.func.id == 'set' and node.args == node.keywords == []):
95*cda5da8dSAndroid Build Coastguard Worker            return set()
96*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, Dict):
97*cda5da8dSAndroid Build Coastguard Worker            if len(node.keys) != len(node.values):
98*cda5da8dSAndroid Build Coastguard Worker                _raise_malformed_node(node)
99*cda5da8dSAndroid Build Coastguard Worker            return dict(zip(map(_convert, node.keys),
100*cda5da8dSAndroid Build Coastguard Worker                            map(_convert, node.values)))
101*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
102*cda5da8dSAndroid Build Coastguard Worker            left = _convert_signed_num(node.left)
103*cda5da8dSAndroid Build Coastguard Worker            right = _convert_num(node.right)
104*cda5da8dSAndroid Build Coastguard Worker            if isinstance(left, (int, float)) and isinstance(right, complex):
105*cda5da8dSAndroid Build Coastguard Worker                if isinstance(node.op, Add):
106*cda5da8dSAndroid Build Coastguard Worker                    return left + right
107*cda5da8dSAndroid Build Coastguard Worker                else:
108*cda5da8dSAndroid Build Coastguard Worker                    return left - right
109*cda5da8dSAndroid Build Coastguard Worker        return _convert_signed_num(node)
110*cda5da8dSAndroid Build Coastguard Worker    return _convert(node_or_string)
111*cda5da8dSAndroid Build Coastguard Worker
112*cda5da8dSAndroid Build Coastguard Worker
113*cda5da8dSAndroid Build Coastguard Workerdef dump(node, annotate_fields=True, include_attributes=False, *, indent=None):
114*cda5da8dSAndroid Build Coastguard Worker    """
115*cda5da8dSAndroid Build Coastguard Worker    Return a formatted dump of the tree in node.  This is mainly useful for
116*cda5da8dSAndroid Build Coastguard Worker    debugging purposes.  If annotate_fields is true (by default),
117*cda5da8dSAndroid Build Coastguard Worker    the returned string will show the names and the values for fields.
118*cda5da8dSAndroid Build Coastguard Worker    If annotate_fields is false, the result string will be more compact by
119*cda5da8dSAndroid Build Coastguard Worker    omitting unambiguous field names.  Attributes such as line
120*cda5da8dSAndroid Build Coastguard Worker    numbers and column offsets are not dumped by default.  If this is wanted,
121*cda5da8dSAndroid Build Coastguard Worker    include_attributes can be set to true.  If indent is a non-negative
122*cda5da8dSAndroid Build Coastguard Worker    integer or string, then the tree will be pretty-printed with that indent
123*cda5da8dSAndroid Build Coastguard Worker    level. None (the default) selects the single line representation.
124*cda5da8dSAndroid Build Coastguard Worker    """
125*cda5da8dSAndroid Build Coastguard Worker    def _format(node, level=0):
126*cda5da8dSAndroid Build Coastguard Worker        if indent is not None:
127*cda5da8dSAndroid Build Coastguard Worker            level += 1
128*cda5da8dSAndroid Build Coastguard Worker            prefix = '\n' + indent * level
129*cda5da8dSAndroid Build Coastguard Worker            sep = ',\n' + indent * level
130*cda5da8dSAndroid Build Coastguard Worker        else:
131*cda5da8dSAndroid Build Coastguard Worker            prefix = ''
132*cda5da8dSAndroid Build Coastguard Worker            sep = ', '
133*cda5da8dSAndroid Build Coastguard Worker        if isinstance(node, AST):
134*cda5da8dSAndroid Build Coastguard Worker            cls = type(node)
135*cda5da8dSAndroid Build Coastguard Worker            args = []
136*cda5da8dSAndroid Build Coastguard Worker            allsimple = True
137*cda5da8dSAndroid Build Coastguard Worker            keywords = annotate_fields
138*cda5da8dSAndroid Build Coastguard Worker            for name in node._fields:
139*cda5da8dSAndroid Build Coastguard Worker                try:
140*cda5da8dSAndroid Build Coastguard Worker                    value = getattr(node, name)
141*cda5da8dSAndroid Build Coastguard Worker                except AttributeError:
142*cda5da8dSAndroid Build Coastguard Worker                    keywords = True
143*cda5da8dSAndroid Build Coastguard Worker                    continue
144*cda5da8dSAndroid Build Coastguard Worker                if value is None and getattr(cls, name, ...) is None:
145*cda5da8dSAndroid Build Coastguard Worker                    keywords = True
146*cda5da8dSAndroid Build Coastguard Worker                    continue
147*cda5da8dSAndroid Build Coastguard Worker                value, simple = _format(value, level)
148*cda5da8dSAndroid Build Coastguard Worker                allsimple = allsimple and simple
149*cda5da8dSAndroid Build Coastguard Worker                if keywords:
150*cda5da8dSAndroid Build Coastguard Worker                    args.append('%s=%s' % (name, value))
151*cda5da8dSAndroid Build Coastguard Worker                else:
152*cda5da8dSAndroid Build Coastguard Worker                    args.append(value)
153*cda5da8dSAndroid Build Coastguard Worker            if include_attributes and node._attributes:
154*cda5da8dSAndroid Build Coastguard Worker                for name in node._attributes:
155*cda5da8dSAndroid Build Coastguard Worker                    try:
156*cda5da8dSAndroid Build Coastguard Worker                        value = getattr(node, name)
157*cda5da8dSAndroid Build Coastguard Worker                    except AttributeError:
158*cda5da8dSAndroid Build Coastguard Worker                        continue
159*cda5da8dSAndroid Build Coastguard Worker                    if value is None and getattr(cls, name, ...) is None:
160*cda5da8dSAndroid Build Coastguard Worker                        continue
161*cda5da8dSAndroid Build Coastguard Worker                    value, simple = _format(value, level)
162*cda5da8dSAndroid Build Coastguard Worker                    allsimple = allsimple and simple
163*cda5da8dSAndroid Build Coastguard Worker                    args.append('%s=%s' % (name, value))
164*cda5da8dSAndroid Build Coastguard Worker            if allsimple and len(args) <= 3:
165*cda5da8dSAndroid Build Coastguard Worker                return '%s(%s)' % (node.__class__.__name__, ', '.join(args)), not args
166*cda5da8dSAndroid Build Coastguard Worker            return '%s(%s%s)' % (node.__class__.__name__, prefix, sep.join(args)), False
167*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, list):
168*cda5da8dSAndroid Build Coastguard Worker            if not node:
169*cda5da8dSAndroid Build Coastguard Worker                return '[]', True
170*cda5da8dSAndroid Build Coastguard Worker            return '[%s%s]' % (prefix, sep.join(_format(x, level)[0] for x in node)), False
171*cda5da8dSAndroid Build Coastguard Worker        return repr(node), True
172*cda5da8dSAndroid Build Coastguard Worker
173*cda5da8dSAndroid Build Coastguard Worker    if not isinstance(node, AST):
174*cda5da8dSAndroid Build Coastguard Worker        raise TypeError('expected AST, got %r' % node.__class__.__name__)
175*cda5da8dSAndroid Build Coastguard Worker    if indent is not None and not isinstance(indent, str):
176*cda5da8dSAndroid Build Coastguard Worker        indent = ' ' * indent
177*cda5da8dSAndroid Build Coastguard Worker    return _format(node)[0]
178*cda5da8dSAndroid Build Coastguard Worker
179*cda5da8dSAndroid Build Coastguard Worker
180*cda5da8dSAndroid Build Coastguard Workerdef copy_location(new_node, old_node):
181*cda5da8dSAndroid Build Coastguard Worker    """
182*cda5da8dSAndroid Build Coastguard Worker    Copy source location (`lineno`, `col_offset`, `end_lineno`, and `end_col_offset`
183*cda5da8dSAndroid Build Coastguard Worker    attributes) from *old_node* to *new_node* if possible, and return *new_node*.
184*cda5da8dSAndroid Build Coastguard Worker    """
185*cda5da8dSAndroid Build Coastguard Worker    for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset':
186*cda5da8dSAndroid Build Coastguard Worker        if attr in old_node._attributes and attr in new_node._attributes:
187*cda5da8dSAndroid Build Coastguard Worker            value = getattr(old_node, attr, None)
188*cda5da8dSAndroid Build Coastguard Worker            # end_lineno and end_col_offset are optional attributes, and they
189*cda5da8dSAndroid Build Coastguard Worker            # should be copied whether the value is None or not.
190*cda5da8dSAndroid Build Coastguard Worker            if value is not None or (
191*cda5da8dSAndroid Build Coastguard Worker                hasattr(old_node, attr) and attr.startswith("end_")
192*cda5da8dSAndroid Build Coastguard Worker            ):
193*cda5da8dSAndroid Build Coastguard Worker                setattr(new_node, attr, value)
194*cda5da8dSAndroid Build Coastguard Worker    return new_node
195*cda5da8dSAndroid Build Coastguard Worker
196*cda5da8dSAndroid Build Coastguard Worker
197*cda5da8dSAndroid Build Coastguard Workerdef fix_missing_locations(node):
198*cda5da8dSAndroid Build Coastguard Worker    """
199*cda5da8dSAndroid Build Coastguard Worker    When you compile a node tree with compile(), the compiler expects lineno and
200*cda5da8dSAndroid Build Coastguard Worker    col_offset attributes for every node that supports them.  This is rather
201*cda5da8dSAndroid Build Coastguard Worker    tedious to fill in for generated nodes, so this helper adds these attributes
202*cda5da8dSAndroid Build Coastguard Worker    recursively where not already set, by setting them to the values of the
203*cda5da8dSAndroid Build Coastguard Worker    parent node.  It works recursively starting at *node*.
204*cda5da8dSAndroid Build Coastguard Worker    """
205*cda5da8dSAndroid Build Coastguard Worker    def _fix(node, lineno, col_offset, end_lineno, end_col_offset):
206*cda5da8dSAndroid Build Coastguard Worker        if 'lineno' in node._attributes:
207*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(node, 'lineno'):
208*cda5da8dSAndroid Build Coastguard Worker                node.lineno = lineno
209*cda5da8dSAndroid Build Coastguard Worker            else:
210*cda5da8dSAndroid Build Coastguard Worker                lineno = node.lineno
211*cda5da8dSAndroid Build Coastguard Worker        if 'end_lineno' in node._attributes:
212*cda5da8dSAndroid Build Coastguard Worker            if getattr(node, 'end_lineno', None) is None:
213*cda5da8dSAndroid Build Coastguard Worker                node.end_lineno = end_lineno
214*cda5da8dSAndroid Build Coastguard Worker            else:
215*cda5da8dSAndroid Build Coastguard Worker                end_lineno = node.end_lineno
216*cda5da8dSAndroid Build Coastguard Worker        if 'col_offset' in node._attributes:
217*cda5da8dSAndroid Build Coastguard Worker            if not hasattr(node, 'col_offset'):
218*cda5da8dSAndroid Build Coastguard Worker                node.col_offset = col_offset
219*cda5da8dSAndroid Build Coastguard Worker            else:
220*cda5da8dSAndroid Build Coastguard Worker                col_offset = node.col_offset
221*cda5da8dSAndroid Build Coastguard Worker        if 'end_col_offset' in node._attributes:
222*cda5da8dSAndroid Build Coastguard Worker            if getattr(node, 'end_col_offset', None) is None:
223*cda5da8dSAndroid Build Coastguard Worker                node.end_col_offset = end_col_offset
224*cda5da8dSAndroid Build Coastguard Worker            else:
225*cda5da8dSAndroid Build Coastguard Worker                end_col_offset = node.end_col_offset
226*cda5da8dSAndroid Build Coastguard Worker        for child in iter_child_nodes(node):
227*cda5da8dSAndroid Build Coastguard Worker            _fix(child, lineno, col_offset, end_lineno, end_col_offset)
228*cda5da8dSAndroid Build Coastguard Worker    _fix(node, 1, 0, 1, 0)
229*cda5da8dSAndroid Build Coastguard Worker    return node
230*cda5da8dSAndroid Build Coastguard Worker
231*cda5da8dSAndroid Build Coastguard Worker
232*cda5da8dSAndroid Build Coastguard Workerdef increment_lineno(node, n=1):
233*cda5da8dSAndroid Build Coastguard Worker    """
234*cda5da8dSAndroid Build Coastguard Worker    Increment the line number and end line number of each node in the tree
235*cda5da8dSAndroid Build Coastguard Worker    starting at *node* by *n*. This is useful to "move code" to a different
236*cda5da8dSAndroid Build Coastguard Worker    location in a file.
237*cda5da8dSAndroid Build Coastguard Worker    """
238*cda5da8dSAndroid Build Coastguard Worker    for child in walk(node):
239*cda5da8dSAndroid Build Coastguard Worker        # TypeIgnore is a special case where lineno is not an attribute
240*cda5da8dSAndroid Build Coastguard Worker        # but rather a field of the node itself.
241*cda5da8dSAndroid Build Coastguard Worker        if isinstance(child, TypeIgnore):
242*cda5da8dSAndroid Build Coastguard Worker            child.lineno = getattr(child, 'lineno', 0) + n
243*cda5da8dSAndroid Build Coastguard Worker            continue
244*cda5da8dSAndroid Build Coastguard Worker
245*cda5da8dSAndroid Build Coastguard Worker        if 'lineno' in child._attributes:
246*cda5da8dSAndroid Build Coastguard Worker            child.lineno = getattr(child, 'lineno', 0) + n
247*cda5da8dSAndroid Build Coastguard Worker        if (
248*cda5da8dSAndroid Build Coastguard Worker            "end_lineno" in child._attributes
249*cda5da8dSAndroid Build Coastguard Worker            and (end_lineno := getattr(child, "end_lineno", 0)) is not None
250*cda5da8dSAndroid Build Coastguard Worker        ):
251*cda5da8dSAndroid Build Coastguard Worker            child.end_lineno = end_lineno + n
252*cda5da8dSAndroid Build Coastguard Worker    return node
253*cda5da8dSAndroid Build Coastguard Worker
254*cda5da8dSAndroid Build Coastguard Worker
255*cda5da8dSAndroid Build Coastguard Workerdef iter_fields(node):
256*cda5da8dSAndroid Build Coastguard Worker    """
257*cda5da8dSAndroid Build Coastguard Worker    Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
258*cda5da8dSAndroid Build Coastguard Worker    that is present on *node*.
259*cda5da8dSAndroid Build Coastguard Worker    """
260*cda5da8dSAndroid Build Coastguard Worker    for field in node._fields:
261*cda5da8dSAndroid Build Coastguard Worker        try:
262*cda5da8dSAndroid Build Coastguard Worker            yield field, getattr(node, field)
263*cda5da8dSAndroid Build Coastguard Worker        except AttributeError:
264*cda5da8dSAndroid Build Coastguard Worker            pass
265*cda5da8dSAndroid Build Coastguard Worker
266*cda5da8dSAndroid Build Coastguard Worker
267*cda5da8dSAndroid Build Coastguard Workerdef iter_child_nodes(node):
268*cda5da8dSAndroid Build Coastguard Worker    """
269*cda5da8dSAndroid Build Coastguard Worker    Yield all direct child nodes of *node*, that is, all fields that are nodes
270*cda5da8dSAndroid Build Coastguard Worker    and all items of fields that are lists of nodes.
271*cda5da8dSAndroid Build Coastguard Worker    """
272*cda5da8dSAndroid Build Coastguard Worker    for name, field in iter_fields(node):
273*cda5da8dSAndroid Build Coastguard Worker        if isinstance(field, AST):
274*cda5da8dSAndroid Build Coastguard Worker            yield field
275*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(field, list):
276*cda5da8dSAndroid Build Coastguard Worker            for item in field:
277*cda5da8dSAndroid Build Coastguard Worker                if isinstance(item, AST):
278*cda5da8dSAndroid Build Coastguard Worker                    yield item
279*cda5da8dSAndroid Build Coastguard Worker
280*cda5da8dSAndroid Build Coastguard Worker
281*cda5da8dSAndroid Build Coastguard Workerdef get_docstring(node, clean=True):
282*cda5da8dSAndroid Build Coastguard Worker    """
283*cda5da8dSAndroid Build Coastguard Worker    Return the docstring for the given node or None if no docstring can
284*cda5da8dSAndroid Build Coastguard Worker    be found.  If the node provided does not have docstrings a TypeError
285*cda5da8dSAndroid Build Coastguard Worker    will be raised.
286*cda5da8dSAndroid Build Coastguard Worker
287*cda5da8dSAndroid Build Coastguard Worker    If *clean* is `True`, all tabs are expanded to spaces and any whitespace
288*cda5da8dSAndroid Build Coastguard Worker    that can be uniformly removed from the second line onwards is removed.
289*cda5da8dSAndroid Build Coastguard Worker    """
290*cda5da8dSAndroid Build Coastguard Worker    if not isinstance(node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)):
291*cda5da8dSAndroid Build Coastguard Worker        raise TypeError("%r can't have docstrings" % node.__class__.__name__)
292*cda5da8dSAndroid Build Coastguard Worker    if not(node.body and isinstance(node.body[0], Expr)):
293*cda5da8dSAndroid Build Coastguard Worker        return None
294*cda5da8dSAndroid Build Coastguard Worker    node = node.body[0].value
295*cda5da8dSAndroid Build Coastguard Worker    if isinstance(node, Str):
296*cda5da8dSAndroid Build Coastguard Worker        text = node.s
297*cda5da8dSAndroid Build Coastguard Worker    elif isinstance(node, Constant) and isinstance(node.value, str):
298*cda5da8dSAndroid Build Coastguard Worker        text = node.value
299*cda5da8dSAndroid Build Coastguard Worker    else:
300*cda5da8dSAndroid Build Coastguard Worker        return None
301*cda5da8dSAndroid Build Coastguard Worker    if clean:
302*cda5da8dSAndroid Build Coastguard Worker        import inspect
303*cda5da8dSAndroid Build Coastguard Worker        text = inspect.cleandoc(text)
304*cda5da8dSAndroid Build Coastguard Worker    return text
305*cda5da8dSAndroid Build Coastguard Worker
306*cda5da8dSAndroid Build Coastguard Worker
307*cda5da8dSAndroid Build Coastguard Workerdef _splitlines_no_ff(source):
308*cda5da8dSAndroid Build Coastguard Worker    """Split a string into lines ignoring form feed and other chars.
309*cda5da8dSAndroid Build Coastguard Worker
310*cda5da8dSAndroid Build Coastguard Worker    This mimics how the Python parser splits source code.
311*cda5da8dSAndroid Build Coastguard Worker    """
312*cda5da8dSAndroid Build Coastguard Worker    idx = 0
313*cda5da8dSAndroid Build Coastguard Worker    lines = []
314*cda5da8dSAndroid Build Coastguard Worker    next_line = ''
315*cda5da8dSAndroid Build Coastguard Worker    while idx < len(source):
316*cda5da8dSAndroid Build Coastguard Worker        c = source[idx]
317*cda5da8dSAndroid Build Coastguard Worker        next_line += c
318*cda5da8dSAndroid Build Coastguard Worker        idx += 1
319*cda5da8dSAndroid Build Coastguard Worker        # Keep \r\n together
320*cda5da8dSAndroid Build Coastguard Worker        if c == '\r' and idx < len(source) and source[idx] == '\n':
321*cda5da8dSAndroid Build Coastguard Worker            next_line += '\n'
322*cda5da8dSAndroid Build Coastguard Worker            idx += 1
323*cda5da8dSAndroid Build Coastguard Worker        if c in '\r\n':
324*cda5da8dSAndroid Build Coastguard Worker            lines.append(next_line)
325*cda5da8dSAndroid Build Coastguard Worker            next_line = ''
326*cda5da8dSAndroid Build Coastguard Worker
327*cda5da8dSAndroid Build Coastguard Worker    if next_line:
328*cda5da8dSAndroid Build Coastguard Worker        lines.append(next_line)
329*cda5da8dSAndroid Build Coastguard Worker    return lines
330*cda5da8dSAndroid Build Coastguard Worker
331*cda5da8dSAndroid Build Coastguard Worker
332*cda5da8dSAndroid Build Coastguard Workerdef _pad_whitespace(source):
333*cda5da8dSAndroid Build Coastguard Worker    r"""Replace all chars except '\f\t' in a line with spaces."""
334*cda5da8dSAndroid Build Coastguard Worker    result = ''
335*cda5da8dSAndroid Build Coastguard Worker    for c in source:
336*cda5da8dSAndroid Build Coastguard Worker        if c in '\f\t':
337*cda5da8dSAndroid Build Coastguard Worker            result += c
338*cda5da8dSAndroid Build Coastguard Worker        else:
339*cda5da8dSAndroid Build Coastguard Worker            result += ' '
340*cda5da8dSAndroid Build Coastguard Worker    return result
341*cda5da8dSAndroid Build Coastguard Worker
342*cda5da8dSAndroid Build Coastguard Worker
343*cda5da8dSAndroid Build Coastguard Workerdef get_source_segment(source, node, *, padded=False):
344*cda5da8dSAndroid Build Coastguard Worker    """Get source code segment of the *source* that generated *node*.
345*cda5da8dSAndroid Build Coastguard Worker
346*cda5da8dSAndroid Build Coastguard Worker    If some location information (`lineno`, `end_lineno`, `col_offset`,
347*cda5da8dSAndroid Build Coastguard Worker    or `end_col_offset`) is missing, return None.
348*cda5da8dSAndroid Build Coastguard Worker
349*cda5da8dSAndroid Build Coastguard Worker    If *padded* is `True`, the first line of a multi-line statement will
350*cda5da8dSAndroid Build Coastguard Worker    be padded with spaces to match its original position.
351*cda5da8dSAndroid Build Coastguard Worker    """
352*cda5da8dSAndroid Build Coastguard Worker    try:
353*cda5da8dSAndroid Build Coastguard Worker        if node.end_lineno is None or node.end_col_offset is None:
354*cda5da8dSAndroid Build Coastguard Worker            return None
355*cda5da8dSAndroid Build Coastguard Worker        lineno = node.lineno - 1
356*cda5da8dSAndroid Build Coastguard Worker        end_lineno = node.end_lineno - 1
357*cda5da8dSAndroid Build Coastguard Worker        col_offset = node.col_offset
358*cda5da8dSAndroid Build Coastguard Worker        end_col_offset = node.end_col_offset
359*cda5da8dSAndroid Build Coastguard Worker    except AttributeError:
360*cda5da8dSAndroid Build Coastguard Worker        return None
361*cda5da8dSAndroid Build Coastguard Worker
362*cda5da8dSAndroid Build Coastguard Worker    lines = _splitlines_no_ff(source)
363*cda5da8dSAndroid Build Coastguard Worker    if end_lineno == lineno:
364*cda5da8dSAndroid Build Coastguard Worker        return lines[lineno].encode()[col_offset:end_col_offset].decode()
365*cda5da8dSAndroid Build Coastguard Worker
366*cda5da8dSAndroid Build Coastguard Worker    if padded:
367*cda5da8dSAndroid Build Coastguard Worker        padding = _pad_whitespace(lines[lineno].encode()[:col_offset].decode())
368*cda5da8dSAndroid Build Coastguard Worker    else:
369*cda5da8dSAndroid Build Coastguard Worker        padding = ''
370*cda5da8dSAndroid Build Coastguard Worker
371*cda5da8dSAndroid Build Coastguard Worker    first = padding + lines[lineno].encode()[col_offset:].decode()
372*cda5da8dSAndroid Build Coastguard Worker    last = lines[end_lineno].encode()[:end_col_offset].decode()
373*cda5da8dSAndroid Build Coastguard Worker    lines = lines[lineno+1:end_lineno]
374*cda5da8dSAndroid Build Coastguard Worker
375*cda5da8dSAndroid Build Coastguard Worker    lines.insert(0, first)
376*cda5da8dSAndroid Build Coastguard Worker    lines.append(last)
377*cda5da8dSAndroid Build Coastguard Worker    return ''.join(lines)
378*cda5da8dSAndroid Build Coastguard Worker
379*cda5da8dSAndroid Build Coastguard Worker
380*cda5da8dSAndroid Build Coastguard Workerdef walk(node):
381*cda5da8dSAndroid Build Coastguard Worker    """
382*cda5da8dSAndroid Build Coastguard Worker    Recursively yield all descendant nodes in the tree starting at *node*
383*cda5da8dSAndroid Build Coastguard Worker    (including *node* itself), in no specified order.  This is useful if you
384*cda5da8dSAndroid Build Coastguard Worker    only want to modify nodes in place and don't care about the context.
385*cda5da8dSAndroid Build Coastguard Worker    """
386*cda5da8dSAndroid Build Coastguard Worker    from collections import deque
387*cda5da8dSAndroid Build Coastguard Worker    todo = deque([node])
388*cda5da8dSAndroid Build Coastguard Worker    while todo:
389*cda5da8dSAndroid Build Coastguard Worker        node = todo.popleft()
390*cda5da8dSAndroid Build Coastguard Worker        todo.extend(iter_child_nodes(node))
391*cda5da8dSAndroid Build Coastguard Worker        yield node
392*cda5da8dSAndroid Build Coastguard Worker
393*cda5da8dSAndroid Build Coastguard Worker
394*cda5da8dSAndroid Build Coastguard Workerclass NodeVisitor(object):
395*cda5da8dSAndroid Build Coastguard Worker    """
396*cda5da8dSAndroid Build Coastguard Worker    A node visitor base class that walks the abstract syntax tree and calls a
397*cda5da8dSAndroid Build Coastguard Worker    visitor function for every node found.  This function may return a value
398*cda5da8dSAndroid Build Coastguard Worker    which is forwarded by the `visit` method.
399*cda5da8dSAndroid Build Coastguard Worker
400*cda5da8dSAndroid Build Coastguard Worker    This class is meant to be subclassed, with the subclass adding visitor
401*cda5da8dSAndroid Build Coastguard Worker    methods.
402*cda5da8dSAndroid Build Coastguard Worker
403*cda5da8dSAndroid Build Coastguard Worker    Per default the visitor functions for the nodes are ``'visit_'`` +
404*cda5da8dSAndroid Build Coastguard Worker    class name of the node.  So a `TryFinally` node visit function would
405*cda5da8dSAndroid Build Coastguard Worker    be `visit_TryFinally`.  This behavior can be changed by overriding
406*cda5da8dSAndroid Build Coastguard Worker    the `visit` method.  If no visitor function exists for a node
407*cda5da8dSAndroid Build Coastguard Worker    (return value `None`) the `generic_visit` visitor is used instead.
408*cda5da8dSAndroid Build Coastguard Worker
409*cda5da8dSAndroid Build Coastguard Worker    Don't use the `NodeVisitor` if you want to apply changes to nodes during
410*cda5da8dSAndroid Build Coastguard Worker    traversing.  For this a special visitor exists (`NodeTransformer`) that
411*cda5da8dSAndroid Build Coastguard Worker    allows modifications.
412*cda5da8dSAndroid Build Coastguard Worker    """
413*cda5da8dSAndroid Build Coastguard Worker
414*cda5da8dSAndroid Build Coastguard Worker    def visit(self, node):
415*cda5da8dSAndroid Build Coastguard Worker        """Visit a node."""
416*cda5da8dSAndroid Build Coastguard Worker        method = 'visit_' + node.__class__.__name__
417*cda5da8dSAndroid Build Coastguard Worker        visitor = getattr(self, method, self.generic_visit)
418*cda5da8dSAndroid Build Coastguard Worker        return visitor(node)
419*cda5da8dSAndroid Build Coastguard Worker
420*cda5da8dSAndroid Build Coastguard Worker    def generic_visit(self, node):
421*cda5da8dSAndroid Build Coastguard Worker        """Called if no explicit visitor function exists for a node."""
422*cda5da8dSAndroid Build Coastguard Worker        for field, value in iter_fields(node):
423*cda5da8dSAndroid Build Coastguard Worker            if isinstance(value, list):
424*cda5da8dSAndroid Build Coastguard Worker                for item in value:
425*cda5da8dSAndroid Build Coastguard Worker                    if isinstance(item, AST):
426*cda5da8dSAndroid Build Coastguard Worker                        self.visit(item)
427*cda5da8dSAndroid Build Coastguard Worker            elif isinstance(value, AST):
428*cda5da8dSAndroid Build Coastguard Worker                self.visit(value)
429*cda5da8dSAndroid Build Coastguard Worker
430*cda5da8dSAndroid Build Coastguard Worker    def visit_Constant(self, node):
431*cda5da8dSAndroid Build Coastguard Worker        value = node.value
432*cda5da8dSAndroid Build Coastguard Worker        type_name = _const_node_type_names.get(type(value))
433*cda5da8dSAndroid Build Coastguard Worker        if type_name is None:
434*cda5da8dSAndroid Build Coastguard Worker            for cls, name in _const_node_type_names.items():
435*cda5da8dSAndroid Build Coastguard Worker                if isinstance(value, cls):
436*cda5da8dSAndroid Build Coastguard Worker                    type_name = name
437*cda5da8dSAndroid Build Coastguard Worker                    break
438*cda5da8dSAndroid Build Coastguard Worker        if type_name is not None:
439*cda5da8dSAndroid Build Coastguard Worker            method = 'visit_' + type_name
440*cda5da8dSAndroid Build Coastguard Worker            try:
441*cda5da8dSAndroid Build Coastguard Worker                visitor = getattr(self, method)
442*cda5da8dSAndroid Build Coastguard Worker            except AttributeError:
443*cda5da8dSAndroid Build Coastguard Worker                pass
444*cda5da8dSAndroid Build Coastguard Worker            else:
445*cda5da8dSAndroid Build Coastguard Worker                import warnings
446*cda5da8dSAndroid Build Coastguard Worker                warnings.warn(f"{method} is deprecated; add visit_Constant",
447*cda5da8dSAndroid Build Coastguard Worker                              DeprecationWarning, 2)
448*cda5da8dSAndroid Build Coastguard Worker                return visitor(node)
449*cda5da8dSAndroid Build Coastguard Worker        return self.generic_visit(node)
450*cda5da8dSAndroid Build Coastguard Worker
451*cda5da8dSAndroid Build Coastguard Worker
452*cda5da8dSAndroid Build Coastguard Workerclass NodeTransformer(NodeVisitor):
453*cda5da8dSAndroid Build Coastguard Worker    """
454*cda5da8dSAndroid Build Coastguard Worker    A :class:`NodeVisitor` subclass that walks the abstract syntax tree and
455*cda5da8dSAndroid Build Coastguard Worker    allows modification of nodes.
456*cda5da8dSAndroid Build Coastguard Worker
457*cda5da8dSAndroid Build Coastguard Worker    The `NodeTransformer` will walk the AST and use the return value of the
458*cda5da8dSAndroid Build Coastguard Worker    visitor methods to replace or remove the old node.  If the return value of
459*cda5da8dSAndroid Build Coastguard Worker    the visitor method is ``None``, the node will be removed from its location,
460*cda5da8dSAndroid Build Coastguard Worker    otherwise it is replaced with the return value.  The return value may be the
461*cda5da8dSAndroid Build Coastguard Worker    original node in which case no replacement takes place.
462*cda5da8dSAndroid Build Coastguard Worker
463*cda5da8dSAndroid Build Coastguard Worker    Here is an example transformer that rewrites all occurrences of name lookups
464*cda5da8dSAndroid Build Coastguard Worker    (``foo``) to ``data['foo']``::
465*cda5da8dSAndroid Build Coastguard Worker
466*cda5da8dSAndroid Build Coastguard Worker       class RewriteName(NodeTransformer):
467*cda5da8dSAndroid Build Coastguard Worker
468*cda5da8dSAndroid Build Coastguard Worker           def visit_Name(self, node):
469*cda5da8dSAndroid Build Coastguard Worker               return Subscript(
470*cda5da8dSAndroid Build Coastguard Worker                   value=Name(id='data', ctx=Load()),
471*cda5da8dSAndroid Build Coastguard Worker                   slice=Constant(value=node.id),
472*cda5da8dSAndroid Build Coastguard Worker                   ctx=node.ctx
473*cda5da8dSAndroid Build Coastguard Worker               )
474*cda5da8dSAndroid Build Coastguard Worker
475*cda5da8dSAndroid Build Coastguard Worker    Keep in mind that if the node you're operating on has child nodes you must
476*cda5da8dSAndroid Build Coastguard Worker    either transform the child nodes yourself or call the :meth:`generic_visit`
477*cda5da8dSAndroid Build Coastguard Worker    method for the node first.
478*cda5da8dSAndroid Build Coastguard Worker
479*cda5da8dSAndroid Build Coastguard Worker    For nodes that were part of a collection of statements (that applies to all
480*cda5da8dSAndroid Build Coastguard Worker    statement nodes), the visitor may also return a list of nodes rather than
481*cda5da8dSAndroid Build Coastguard Worker    just a single node.
482*cda5da8dSAndroid Build Coastguard Worker
483*cda5da8dSAndroid Build Coastguard Worker    Usually you use the transformer like this::
484*cda5da8dSAndroid Build Coastguard Worker
485*cda5da8dSAndroid Build Coastguard Worker       node = YourTransformer().visit(node)
486*cda5da8dSAndroid Build Coastguard Worker    """
487*cda5da8dSAndroid Build Coastguard Worker
488*cda5da8dSAndroid Build Coastguard Worker    def generic_visit(self, node):
489*cda5da8dSAndroid Build Coastguard Worker        for field, old_value in iter_fields(node):
490*cda5da8dSAndroid Build Coastguard Worker            if isinstance(old_value, list):
491*cda5da8dSAndroid Build Coastguard Worker                new_values = []
492*cda5da8dSAndroid Build Coastguard Worker                for value in old_value:
493*cda5da8dSAndroid Build Coastguard Worker                    if isinstance(value, AST):
494*cda5da8dSAndroid Build Coastguard Worker                        value = self.visit(value)
495*cda5da8dSAndroid Build Coastguard Worker                        if value is None:
496*cda5da8dSAndroid Build Coastguard Worker                            continue
497*cda5da8dSAndroid Build Coastguard Worker                        elif not isinstance(value, AST):
498*cda5da8dSAndroid Build Coastguard Worker                            new_values.extend(value)
499*cda5da8dSAndroid Build Coastguard Worker                            continue
500*cda5da8dSAndroid Build Coastguard Worker                    new_values.append(value)
501*cda5da8dSAndroid Build Coastguard Worker                old_value[:] = new_values
502*cda5da8dSAndroid Build Coastguard Worker            elif isinstance(old_value, AST):
503*cda5da8dSAndroid Build Coastguard Worker                new_node = self.visit(old_value)
504*cda5da8dSAndroid Build Coastguard Worker                if new_node is None:
505*cda5da8dSAndroid Build Coastguard Worker                    delattr(node, field)
506*cda5da8dSAndroid Build Coastguard Worker                else:
507*cda5da8dSAndroid Build Coastguard Worker                    setattr(node, field, new_node)
508*cda5da8dSAndroid Build Coastguard Worker        return node
509*cda5da8dSAndroid Build Coastguard Worker
510*cda5da8dSAndroid Build Coastguard Worker
511*cda5da8dSAndroid Build Coastguard Worker# If the ast module is loaded more than once, only add deprecated methods once
512*cda5da8dSAndroid Build Coastguard Workerif not hasattr(Constant, 'n'):
513*cda5da8dSAndroid Build Coastguard Worker    # The following code is for backward compatibility.
514*cda5da8dSAndroid Build Coastguard Worker    # It will be removed in future.
515*cda5da8dSAndroid Build Coastguard Worker
516*cda5da8dSAndroid Build Coastguard Worker    def _getter(self):
517*cda5da8dSAndroid Build Coastguard Worker        """Deprecated. Use value instead."""
518*cda5da8dSAndroid Build Coastguard Worker        return self.value
519*cda5da8dSAndroid Build Coastguard Worker
520*cda5da8dSAndroid Build Coastguard Worker    def _setter(self, value):
521*cda5da8dSAndroid Build Coastguard Worker        self.value = value
522*cda5da8dSAndroid Build Coastguard Worker
523*cda5da8dSAndroid Build Coastguard Worker    Constant.n = property(_getter, _setter)
524*cda5da8dSAndroid Build Coastguard Worker    Constant.s = property(_getter, _setter)
525*cda5da8dSAndroid Build Coastguard Worker
526*cda5da8dSAndroid Build Coastguard Workerclass _ABC(type):
527*cda5da8dSAndroid Build Coastguard Worker
528*cda5da8dSAndroid Build Coastguard Worker    def __init__(cls, *args):
529*cda5da8dSAndroid Build Coastguard Worker        cls.__doc__ = """Deprecated AST node class. Use ast.Constant instead"""
530*cda5da8dSAndroid Build Coastguard Worker
531*cda5da8dSAndroid Build Coastguard Worker    def __instancecheck__(cls, inst):
532*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(inst, Constant):
533*cda5da8dSAndroid Build Coastguard Worker            return False
534*cda5da8dSAndroid Build Coastguard Worker        if cls in _const_types:
535*cda5da8dSAndroid Build Coastguard Worker            try:
536*cda5da8dSAndroid Build Coastguard Worker                value = inst.value
537*cda5da8dSAndroid Build Coastguard Worker            except AttributeError:
538*cda5da8dSAndroid Build Coastguard Worker                return False
539*cda5da8dSAndroid Build Coastguard Worker            else:
540*cda5da8dSAndroid Build Coastguard Worker                return (
541*cda5da8dSAndroid Build Coastguard Worker                    isinstance(value, _const_types[cls]) and
542*cda5da8dSAndroid Build Coastguard Worker                    not isinstance(value, _const_types_not.get(cls, ()))
543*cda5da8dSAndroid Build Coastguard Worker                )
544*cda5da8dSAndroid Build Coastguard Worker        return type.__instancecheck__(cls, inst)
545*cda5da8dSAndroid Build Coastguard Worker
546*cda5da8dSAndroid Build Coastguard Workerdef _new(cls, *args, **kwargs):
547*cda5da8dSAndroid Build Coastguard Worker    for key in kwargs:
548*cda5da8dSAndroid Build Coastguard Worker        if key not in cls._fields:
549*cda5da8dSAndroid Build Coastguard Worker            # arbitrary keyword arguments are accepted
550*cda5da8dSAndroid Build Coastguard Worker            continue
551*cda5da8dSAndroid Build Coastguard Worker        pos = cls._fields.index(key)
552*cda5da8dSAndroid Build Coastguard Worker        if pos < len(args):
553*cda5da8dSAndroid Build Coastguard Worker            raise TypeError(f"{cls.__name__} got multiple values for argument {key!r}")
554*cda5da8dSAndroid Build Coastguard Worker    if cls in _const_types:
555*cda5da8dSAndroid Build Coastguard Worker        return Constant(*args, **kwargs)
556*cda5da8dSAndroid Build Coastguard Worker    return Constant.__new__(cls, *args, **kwargs)
557*cda5da8dSAndroid Build Coastguard Worker
558*cda5da8dSAndroid Build Coastguard Workerclass Num(Constant, metaclass=_ABC):
559*cda5da8dSAndroid Build Coastguard Worker    _fields = ('n',)
560*cda5da8dSAndroid Build Coastguard Worker    __new__ = _new
561*cda5da8dSAndroid Build Coastguard Worker
562*cda5da8dSAndroid Build Coastguard Workerclass Str(Constant, metaclass=_ABC):
563*cda5da8dSAndroid Build Coastguard Worker    _fields = ('s',)
564*cda5da8dSAndroid Build Coastguard Worker    __new__ = _new
565*cda5da8dSAndroid Build Coastguard Worker
566*cda5da8dSAndroid Build Coastguard Workerclass Bytes(Constant, metaclass=_ABC):
567*cda5da8dSAndroid Build Coastguard Worker    _fields = ('s',)
568*cda5da8dSAndroid Build Coastguard Worker    __new__ = _new
569*cda5da8dSAndroid Build Coastguard Worker
570*cda5da8dSAndroid Build Coastguard Workerclass NameConstant(Constant, metaclass=_ABC):
571*cda5da8dSAndroid Build Coastguard Worker    __new__ = _new
572*cda5da8dSAndroid Build Coastguard Worker
573*cda5da8dSAndroid Build Coastguard Workerclass Ellipsis(Constant, metaclass=_ABC):
574*cda5da8dSAndroid Build Coastguard Worker    _fields = ()
575*cda5da8dSAndroid Build Coastguard Worker
576*cda5da8dSAndroid Build Coastguard Worker    def __new__(cls, *args, **kwargs):
577*cda5da8dSAndroid Build Coastguard Worker        if cls is Ellipsis:
578*cda5da8dSAndroid Build Coastguard Worker            return Constant(..., *args, **kwargs)
579*cda5da8dSAndroid Build Coastguard Worker        return Constant.__new__(cls, *args, **kwargs)
580*cda5da8dSAndroid Build Coastguard Worker
581*cda5da8dSAndroid Build Coastguard Worker_const_types = {
582*cda5da8dSAndroid Build Coastguard Worker    Num: (int, float, complex),
583*cda5da8dSAndroid Build Coastguard Worker    Str: (str,),
584*cda5da8dSAndroid Build Coastguard Worker    Bytes: (bytes,),
585*cda5da8dSAndroid Build Coastguard Worker    NameConstant: (type(None), bool),
586*cda5da8dSAndroid Build Coastguard Worker    Ellipsis: (type(...),),
587*cda5da8dSAndroid Build Coastguard Worker}
588*cda5da8dSAndroid Build Coastguard Worker_const_types_not = {
589*cda5da8dSAndroid Build Coastguard Worker    Num: (bool,),
590*cda5da8dSAndroid Build Coastguard Worker}
591*cda5da8dSAndroid Build Coastguard Worker
592*cda5da8dSAndroid Build Coastguard Worker_const_node_type_names = {
593*cda5da8dSAndroid Build Coastguard Worker    bool: 'NameConstant',  # should be before int
594*cda5da8dSAndroid Build Coastguard Worker    type(None): 'NameConstant',
595*cda5da8dSAndroid Build Coastguard Worker    int: 'Num',
596*cda5da8dSAndroid Build Coastguard Worker    float: 'Num',
597*cda5da8dSAndroid Build Coastguard Worker    complex: 'Num',
598*cda5da8dSAndroid Build Coastguard Worker    str: 'Str',
599*cda5da8dSAndroid Build Coastguard Worker    bytes: 'Bytes',
600*cda5da8dSAndroid Build Coastguard Worker    type(...): 'Ellipsis',
601*cda5da8dSAndroid Build Coastguard Worker}
602*cda5da8dSAndroid Build Coastguard Worker
603*cda5da8dSAndroid Build Coastguard Workerclass slice(AST):
604*cda5da8dSAndroid Build Coastguard Worker    """Deprecated AST node class."""
605*cda5da8dSAndroid Build Coastguard Worker
606*cda5da8dSAndroid Build Coastguard Workerclass Index(slice):
607*cda5da8dSAndroid Build Coastguard Worker    """Deprecated AST node class. Use the index value directly instead."""
608*cda5da8dSAndroid Build Coastguard Worker    def __new__(cls, value, **kwargs):
609*cda5da8dSAndroid Build Coastguard Worker        return value
610*cda5da8dSAndroid Build Coastguard Worker
611*cda5da8dSAndroid Build Coastguard Workerclass ExtSlice(slice):
612*cda5da8dSAndroid Build Coastguard Worker    """Deprecated AST node class. Use ast.Tuple instead."""
613*cda5da8dSAndroid Build Coastguard Worker    def __new__(cls, dims=(), **kwargs):
614*cda5da8dSAndroid Build Coastguard Worker        return Tuple(list(dims), Load(), **kwargs)
615*cda5da8dSAndroid Build Coastguard Worker
616*cda5da8dSAndroid Build Coastguard Worker# If the ast module is loaded more than once, only add deprecated methods once
617*cda5da8dSAndroid Build Coastguard Workerif not hasattr(Tuple, 'dims'):
618*cda5da8dSAndroid Build Coastguard Worker    # The following code is for backward compatibility.
619*cda5da8dSAndroid Build Coastguard Worker    # It will be removed in future.
620*cda5da8dSAndroid Build Coastguard Worker
621*cda5da8dSAndroid Build Coastguard Worker    def _dims_getter(self):
622*cda5da8dSAndroid Build Coastguard Worker        """Deprecated. Use elts instead."""
623*cda5da8dSAndroid Build Coastguard Worker        return self.elts
624*cda5da8dSAndroid Build Coastguard Worker
625*cda5da8dSAndroid Build Coastguard Worker    def _dims_setter(self, value):
626*cda5da8dSAndroid Build Coastguard Worker        self.elts = value
627*cda5da8dSAndroid Build Coastguard Worker
628*cda5da8dSAndroid Build Coastguard Worker    Tuple.dims = property(_dims_getter, _dims_setter)
629*cda5da8dSAndroid Build Coastguard Worker
630*cda5da8dSAndroid Build Coastguard Workerclass Suite(mod):
631*cda5da8dSAndroid Build Coastguard Worker    """Deprecated AST node class.  Unused in Python 3."""
632*cda5da8dSAndroid Build Coastguard Worker
633*cda5da8dSAndroid Build Coastguard Workerclass AugLoad(expr_context):
634*cda5da8dSAndroid Build Coastguard Worker    """Deprecated AST node class.  Unused in Python 3."""
635*cda5da8dSAndroid Build Coastguard Worker
636*cda5da8dSAndroid Build Coastguard Workerclass AugStore(expr_context):
637*cda5da8dSAndroid Build Coastguard Worker    """Deprecated AST node class.  Unused in Python 3."""
638*cda5da8dSAndroid Build Coastguard Worker
639*cda5da8dSAndroid Build Coastguard Workerclass Param(expr_context):
640*cda5da8dSAndroid Build Coastguard Worker    """Deprecated AST node class.  Unused in Python 3."""
641*cda5da8dSAndroid Build Coastguard Worker
642*cda5da8dSAndroid Build Coastguard Worker
643*cda5da8dSAndroid Build Coastguard Worker# Large float and imaginary literals get turned into infinities in the AST.
644*cda5da8dSAndroid Build Coastguard Worker# We unparse those infinities to INFSTR.
645*cda5da8dSAndroid Build Coastguard Worker_INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1)
646*cda5da8dSAndroid Build Coastguard Worker
647*cda5da8dSAndroid Build Coastguard Worker@_simple_enum(IntEnum)
648*cda5da8dSAndroid Build Coastguard Workerclass _Precedence:
649*cda5da8dSAndroid Build Coastguard Worker    """Precedence table that originated from python grammar."""
650*cda5da8dSAndroid Build Coastguard Worker
651*cda5da8dSAndroid Build Coastguard Worker    NAMED_EXPR = auto()      # <target> := <expr1>
652*cda5da8dSAndroid Build Coastguard Worker    TUPLE = auto()           # <expr1>, <expr2>
653*cda5da8dSAndroid Build Coastguard Worker    YIELD = auto()           # 'yield', 'yield from'
654*cda5da8dSAndroid Build Coastguard Worker    TEST = auto()            # 'if'-'else', 'lambda'
655*cda5da8dSAndroid Build Coastguard Worker    OR = auto()              # 'or'
656*cda5da8dSAndroid Build Coastguard Worker    AND = auto()             # 'and'
657*cda5da8dSAndroid Build Coastguard Worker    NOT = auto()             # 'not'
658*cda5da8dSAndroid Build Coastguard Worker    CMP = auto()             # '<', '>', '==', '>=', '<=', '!=',
659*cda5da8dSAndroid Build Coastguard Worker                             # 'in', 'not in', 'is', 'is not'
660*cda5da8dSAndroid Build Coastguard Worker    EXPR = auto()
661*cda5da8dSAndroid Build Coastguard Worker    BOR = EXPR               # '|'
662*cda5da8dSAndroid Build Coastguard Worker    BXOR = auto()            # '^'
663*cda5da8dSAndroid Build Coastguard Worker    BAND = auto()            # '&'
664*cda5da8dSAndroid Build Coastguard Worker    SHIFT = auto()           # '<<', '>>'
665*cda5da8dSAndroid Build Coastguard Worker    ARITH = auto()           # '+', '-'
666*cda5da8dSAndroid Build Coastguard Worker    TERM = auto()            # '*', '@', '/', '%', '//'
667*cda5da8dSAndroid Build Coastguard Worker    FACTOR = auto()          # unary '+', '-', '~'
668*cda5da8dSAndroid Build Coastguard Worker    POWER = auto()           # '**'
669*cda5da8dSAndroid Build Coastguard Worker    AWAIT = auto()           # 'await'
670*cda5da8dSAndroid Build Coastguard Worker    ATOM = auto()
671*cda5da8dSAndroid Build Coastguard Worker
672*cda5da8dSAndroid Build Coastguard Worker    def next(self):
673*cda5da8dSAndroid Build Coastguard Worker        try:
674*cda5da8dSAndroid Build Coastguard Worker            return self.__class__(self + 1)
675*cda5da8dSAndroid Build Coastguard Worker        except ValueError:
676*cda5da8dSAndroid Build Coastguard Worker            return self
677*cda5da8dSAndroid Build Coastguard Worker
678*cda5da8dSAndroid Build Coastguard Worker
679*cda5da8dSAndroid Build Coastguard Worker_SINGLE_QUOTES = ("'", '"')
680*cda5da8dSAndroid Build Coastguard Worker_MULTI_QUOTES = ('"""', "'''")
681*cda5da8dSAndroid Build Coastguard Worker_ALL_QUOTES = (*_SINGLE_QUOTES, *_MULTI_QUOTES)
682*cda5da8dSAndroid Build Coastguard Worker
683*cda5da8dSAndroid Build Coastguard Workerclass _Unparser(NodeVisitor):
684*cda5da8dSAndroid Build Coastguard Worker    """Methods in this class recursively traverse an AST and
685*cda5da8dSAndroid Build Coastguard Worker    output source code for the abstract syntax; original formatting
686*cda5da8dSAndroid Build Coastguard Worker    is disregarded."""
687*cda5da8dSAndroid Build Coastguard Worker
688*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, *, _avoid_backslashes=False):
689*cda5da8dSAndroid Build Coastguard Worker        self._source = []
690*cda5da8dSAndroid Build Coastguard Worker        self._precedences = {}
691*cda5da8dSAndroid Build Coastguard Worker        self._type_ignores = {}
692*cda5da8dSAndroid Build Coastguard Worker        self._indent = 0
693*cda5da8dSAndroid Build Coastguard Worker        self._avoid_backslashes = _avoid_backslashes
694*cda5da8dSAndroid Build Coastguard Worker        self._in_try_star = False
695*cda5da8dSAndroid Build Coastguard Worker
696*cda5da8dSAndroid Build Coastguard Worker    def interleave(self, inter, f, seq):
697*cda5da8dSAndroid Build Coastguard Worker        """Call f on each item in seq, calling inter() in between."""
698*cda5da8dSAndroid Build Coastguard Worker        seq = iter(seq)
699*cda5da8dSAndroid Build Coastguard Worker        try:
700*cda5da8dSAndroid Build Coastguard Worker            f(next(seq))
701*cda5da8dSAndroid Build Coastguard Worker        except StopIteration:
702*cda5da8dSAndroid Build Coastguard Worker            pass
703*cda5da8dSAndroid Build Coastguard Worker        else:
704*cda5da8dSAndroid Build Coastguard Worker            for x in seq:
705*cda5da8dSAndroid Build Coastguard Worker                inter()
706*cda5da8dSAndroid Build Coastguard Worker                f(x)
707*cda5da8dSAndroid Build Coastguard Worker
708*cda5da8dSAndroid Build Coastguard Worker    def items_view(self, traverser, items):
709*cda5da8dSAndroid Build Coastguard Worker        """Traverse and separate the given *items* with a comma and append it to
710*cda5da8dSAndroid Build Coastguard Worker        the buffer. If *items* is a single item sequence, a trailing comma
711*cda5da8dSAndroid Build Coastguard Worker        will be added."""
712*cda5da8dSAndroid Build Coastguard Worker        if len(items) == 1:
713*cda5da8dSAndroid Build Coastguard Worker            traverser(items[0])
714*cda5da8dSAndroid Build Coastguard Worker            self.write(",")
715*cda5da8dSAndroid Build Coastguard Worker        else:
716*cda5da8dSAndroid Build Coastguard Worker            self.interleave(lambda: self.write(", "), traverser, items)
717*cda5da8dSAndroid Build Coastguard Worker
718*cda5da8dSAndroid Build Coastguard Worker    def maybe_newline(self):
719*cda5da8dSAndroid Build Coastguard Worker        """Adds a newline if it isn't the start of generated source"""
720*cda5da8dSAndroid Build Coastguard Worker        if self._source:
721*cda5da8dSAndroid Build Coastguard Worker            self.write("\n")
722*cda5da8dSAndroid Build Coastguard Worker
723*cda5da8dSAndroid Build Coastguard Worker    def fill(self, text=""):
724*cda5da8dSAndroid Build Coastguard Worker        """Indent a piece of text and append it, according to the current
725*cda5da8dSAndroid Build Coastguard Worker        indentation level"""
726*cda5da8dSAndroid Build Coastguard Worker        self.maybe_newline()
727*cda5da8dSAndroid Build Coastguard Worker        self.write("    " * self._indent + text)
728*cda5da8dSAndroid Build Coastguard Worker
729*cda5da8dSAndroid Build Coastguard Worker    def write(self, *text):
730*cda5da8dSAndroid Build Coastguard Worker        """Add new source parts"""
731*cda5da8dSAndroid Build Coastguard Worker        self._source.extend(text)
732*cda5da8dSAndroid Build Coastguard Worker
733*cda5da8dSAndroid Build Coastguard Worker    @contextmanager
734*cda5da8dSAndroid Build Coastguard Worker    def buffered(self, buffer = None):
735*cda5da8dSAndroid Build Coastguard Worker        if buffer is None:
736*cda5da8dSAndroid Build Coastguard Worker            buffer = []
737*cda5da8dSAndroid Build Coastguard Worker
738*cda5da8dSAndroid Build Coastguard Worker        original_source = self._source
739*cda5da8dSAndroid Build Coastguard Worker        self._source = buffer
740*cda5da8dSAndroid Build Coastguard Worker        yield buffer
741*cda5da8dSAndroid Build Coastguard Worker        self._source = original_source
742*cda5da8dSAndroid Build Coastguard Worker
743*cda5da8dSAndroid Build Coastguard Worker    @contextmanager
744*cda5da8dSAndroid Build Coastguard Worker    def block(self, *, extra = None):
745*cda5da8dSAndroid Build Coastguard Worker        """A context manager for preparing the source for blocks. It adds
746*cda5da8dSAndroid Build Coastguard Worker        the character':', increases the indentation on enter and decreases
747*cda5da8dSAndroid Build Coastguard Worker        the indentation on exit. If *extra* is given, it will be directly
748*cda5da8dSAndroid Build Coastguard Worker        appended after the colon character.
749*cda5da8dSAndroid Build Coastguard Worker        """
750*cda5da8dSAndroid Build Coastguard Worker        self.write(":")
751*cda5da8dSAndroid Build Coastguard Worker        if extra:
752*cda5da8dSAndroid Build Coastguard Worker            self.write(extra)
753*cda5da8dSAndroid Build Coastguard Worker        self._indent += 1
754*cda5da8dSAndroid Build Coastguard Worker        yield
755*cda5da8dSAndroid Build Coastguard Worker        self._indent -= 1
756*cda5da8dSAndroid Build Coastguard Worker
757*cda5da8dSAndroid Build Coastguard Worker    @contextmanager
758*cda5da8dSAndroid Build Coastguard Worker    def delimit(self, start, end):
759*cda5da8dSAndroid Build Coastguard Worker        """A context manager for preparing the source for expressions. It adds
760*cda5da8dSAndroid Build Coastguard Worker        *start* to the buffer and enters, after exit it adds *end*."""
761*cda5da8dSAndroid Build Coastguard Worker
762*cda5da8dSAndroid Build Coastguard Worker        self.write(start)
763*cda5da8dSAndroid Build Coastguard Worker        yield
764*cda5da8dSAndroid Build Coastguard Worker        self.write(end)
765*cda5da8dSAndroid Build Coastguard Worker
766*cda5da8dSAndroid Build Coastguard Worker    def delimit_if(self, start, end, condition):
767*cda5da8dSAndroid Build Coastguard Worker        if condition:
768*cda5da8dSAndroid Build Coastguard Worker            return self.delimit(start, end)
769*cda5da8dSAndroid Build Coastguard Worker        else:
770*cda5da8dSAndroid Build Coastguard Worker            return nullcontext()
771*cda5da8dSAndroid Build Coastguard Worker
772*cda5da8dSAndroid Build Coastguard Worker    def require_parens(self, precedence, node):
773*cda5da8dSAndroid Build Coastguard Worker        """Shortcut to adding precedence related parens"""
774*cda5da8dSAndroid Build Coastguard Worker        return self.delimit_if("(", ")", self.get_precedence(node) > precedence)
775*cda5da8dSAndroid Build Coastguard Worker
776*cda5da8dSAndroid Build Coastguard Worker    def get_precedence(self, node):
777*cda5da8dSAndroid Build Coastguard Worker        return self._precedences.get(node, _Precedence.TEST)
778*cda5da8dSAndroid Build Coastguard Worker
779*cda5da8dSAndroid Build Coastguard Worker    def set_precedence(self, precedence, *nodes):
780*cda5da8dSAndroid Build Coastguard Worker        for node in nodes:
781*cda5da8dSAndroid Build Coastguard Worker            self._precedences[node] = precedence
782*cda5da8dSAndroid Build Coastguard Worker
783*cda5da8dSAndroid Build Coastguard Worker    def get_raw_docstring(self, node):
784*cda5da8dSAndroid Build Coastguard Worker        """If a docstring node is found in the body of the *node* parameter,
785*cda5da8dSAndroid Build Coastguard Worker        return that docstring node, None otherwise.
786*cda5da8dSAndroid Build Coastguard Worker
787*cda5da8dSAndroid Build Coastguard Worker        Logic mirrored from ``_PyAST_GetDocString``."""
788*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(
789*cda5da8dSAndroid Build Coastguard Worker            node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)
790*cda5da8dSAndroid Build Coastguard Worker        ) or len(node.body) < 1:
791*cda5da8dSAndroid Build Coastguard Worker            return None
792*cda5da8dSAndroid Build Coastguard Worker        node = node.body[0]
793*cda5da8dSAndroid Build Coastguard Worker        if not isinstance(node, Expr):
794*cda5da8dSAndroid Build Coastguard Worker            return None
795*cda5da8dSAndroid Build Coastguard Worker        node = node.value
796*cda5da8dSAndroid Build Coastguard Worker        if isinstance(node, Constant) and isinstance(node.value, str):
797*cda5da8dSAndroid Build Coastguard Worker            return node
798*cda5da8dSAndroid Build Coastguard Worker
799*cda5da8dSAndroid Build Coastguard Worker    def get_type_comment(self, node):
800*cda5da8dSAndroid Build Coastguard Worker        comment = self._type_ignores.get(node.lineno) or node.type_comment
801*cda5da8dSAndroid Build Coastguard Worker        if comment is not None:
802*cda5da8dSAndroid Build Coastguard Worker            return f" # type: {comment}"
803*cda5da8dSAndroid Build Coastguard Worker
804*cda5da8dSAndroid Build Coastguard Worker    def traverse(self, node):
805*cda5da8dSAndroid Build Coastguard Worker        if isinstance(node, list):
806*cda5da8dSAndroid Build Coastguard Worker            for item in node:
807*cda5da8dSAndroid Build Coastguard Worker                self.traverse(item)
808*cda5da8dSAndroid Build Coastguard Worker        else:
809*cda5da8dSAndroid Build Coastguard Worker            super().visit(node)
810*cda5da8dSAndroid Build Coastguard Worker
811*cda5da8dSAndroid Build Coastguard Worker    # Note: as visit() resets the output text, do NOT rely on
812*cda5da8dSAndroid Build Coastguard Worker    # NodeVisitor.generic_visit to handle any nodes (as it calls back in to
813*cda5da8dSAndroid Build Coastguard Worker    # the subclass visit() method, which resets self._source to an empty list)
814*cda5da8dSAndroid Build Coastguard Worker    def visit(self, node):
815*cda5da8dSAndroid Build Coastguard Worker        """Outputs a source code string that, if converted back to an ast
816*cda5da8dSAndroid Build Coastguard Worker        (using ast.parse) will generate an AST equivalent to *node*"""
817*cda5da8dSAndroid Build Coastguard Worker        self._source = []
818*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node)
819*cda5da8dSAndroid Build Coastguard Worker        return "".join(self._source)
820*cda5da8dSAndroid Build Coastguard Worker
821*cda5da8dSAndroid Build Coastguard Worker    def _write_docstring_and_traverse_body(self, node):
822*cda5da8dSAndroid Build Coastguard Worker        if (docstring := self.get_raw_docstring(node)):
823*cda5da8dSAndroid Build Coastguard Worker            self._write_docstring(docstring)
824*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body[1:])
825*cda5da8dSAndroid Build Coastguard Worker        else:
826*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
827*cda5da8dSAndroid Build Coastguard Worker
828*cda5da8dSAndroid Build Coastguard Worker    def visit_Module(self, node):
829*cda5da8dSAndroid Build Coastguard Worker        self._type_ignores = {
830*cda5da8dSAndroid Build Coastguard Worker            ignore.lineno: f"ignore{ignore.tag}"
831*cda5da8dSAndroid Build Coastguard Worker            for ignore in node.type_ignores
832*cda5da8dSAndroid Build Coastguard Worker        }
833*cda5da8dSAndroid Build Coastguard Worker        self._write_docstring_and_traverse_body(node)
834*cda5da8dSAndroid Build Coastguard Worker        self._type_ignores.clear()
835*cda5da8dSAndroid Build Coastguard Worker
836*cda5da8dSAndroid Build Coastguard Worker    def visit_FunctionType(self, node):
837*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("(", ")"):
838*cda5da8dSAndroid Build Coastguard Worker            self.interleave(
839*cda5da8dSAndroid Build Coastguard Worker                lambda: self.write(", "), self.traverse, node.argtypes
840*cda5da8dSAndroid Build Coastguard Worker            )
841*cda5da8dSAndroid Build Coastguard Worker
842*cda5da8dSAndroid Build Coastguard Worker        self.write(" -> ")
843*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.returns)
844*cda5da8dSAndroid Build Coastguard Worker
845*cda5da8dSAndroid Build Coastguard Worker    def visit_Expr(self, node):
846*cda5da8dSAndroid Build Coastguard Worker        self.fill()
847*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.YIELD, node.value)
848*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
849*cda5da8dSAndroid Build Coastguard Worker
850*cda5da8dSAndroid Build Coastguard Worker    def visit_NamedExpr(self, node):
851*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.NAMED_EXPR, node):
852*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.ATOM, node.target, node.value)
853*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.target)
854*cda5da8dSAndroid Build Coastguard Worker            self.write(" := ")
855*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.value)
856*cda5da8dSAndroid Build Coastguard Worker
857*cda5da8dSAndroid Build Coastguard Worker    def visit_Import(self, node):
858*cda5da8dSAndroid Build Coastguard Worker        self.fill("import ")
859*cda5da8dSAndroid Build Coastguard Worker        self.interleave(lambda: self.write(", "), self.traverse, node.names)
860*cda5da8dSAndroid Build Coastguard Worker
861*cda5da8dSAndroid Build Coastguard Worker    def visit_ImportFrom(self, node):
862*cda5da8dSAndroid Build Coastguard Worker        self.fill("from ")
863*cda5da8dSAndroid Build Coastguard Worker        self.write("." * (node.level or 0))
864*cda5da8dSAndroid Build Coastguard Worker        if node.module:
865*cda5da8dSAndroid Build Coastguard Worker            self.write(node.module)
866*cda5da8dSAndroid Build Coastguard Worker        self.write(" import ")
867*cda5da8dSAndroid Build Coastguard Worker        self.interleave(lambda: self.write(", "), self.traverse, node.names)
868*cda5da8dSAndroid Build Coastguard Worker
869*cda5da8dSAndroid Build Coastguard Worker    def visit_Assign(self, node):
870*cda5da8dSAndroid Build Coastguard Worker        self.fill()
871*cda5da8dSAndroid Build Coastguard Worker        for target in node.targets:
872*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.TUPLE, target)
873*cda5da8dSAndroid Build Coastguard Worker            self.traverse(target)
874*cda5da8dSAndroid Build Coastguard Worker            self.write(" = ")
875*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
876*cda5da8dSAndroid Build Coastguard Worker        if type_comment := self.get_type_comment(node):
877*cda5da8dSAndroid Build Coastguard Worker            self.write(type_comment)
878*cda5da8dSAndroid Build Coastguard Worker
879*cda5da8dSAndroid Build Coastguard Worker    def visit_AugAssign(self, node):
880*cda5da8dSAndroid Build Coastguard Worker        self.fill()
881*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.target)
882*cda5da8dSAndroid Build Coastguard Worker        self.write(" " + self.binop[node.op.__class__.__name__] + "= ")
883*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
884*cda5da8dSAndroid Build Coastguard Worker
885*cda5da8dSAndroid Build Coastguard Worker    def visit_AnnAssign(self, node):
886*cda5da8dSAndroid Build Coastguard Worker        self.fill()
887*cda5da8dSAndroid Build Coastguard Worker        with self.delimit_if("(", ")", not node.simple and isinstance(node.target, Name)):
888*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.target)
889*cda5da8dSAndroid Build Coastguard Worker        self.write(": ")
890*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.annotation)
891*cda5da8dSAndroid Build Coastguard Worker        if node.value:
892*cda5da8dSAndroid Build Coastguard Worker            self.write(" = ")
893*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.value)
894*cda5da8dSAndroid Build Coastguard Worker
895*cda5da8dSAndroid Build Coastguard Worker    def visit_Return(self, node):
896*cda5da8dSAndroid Build Coastguard Worker        self.fill("return")
897*cda5da8dSAndroid Build Coastguard Worker        if node.value:
898*cda5da8dSAndroid Build Coastguard Worker            self.write(" ")
899*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.value)
900*cda5da8dSAndroid Build Coastguard Worker
901*cda5da8dSAndroid Build Coastguard Worker    def visit_Pass(self, node):
902*cda5da8dSAndroid Build Coastguard Worker        self.fill("pass")
903*cda5da8dSAndroid Build Coastguard Worker
904*cda5da8dSAndroid Build Coastguard Worker    def visit_Break(self, node):
905*cda5da8dSAndroid Build Coastguard Worker        self.fill("break")
906*cda5da8dSAndroid Build Coastguard Worker
907*cda5da8dSAndroid Build Coastguard Worker    def visit_Continue(self, node):
908*cda5da8dSAndroid Build Coastguard Worker        self.fill("continue")
909*cda5da8dSAndroid Build Coastguard Worker
910*cda5da8dSAndroid Build Coastguard Worker    def visit_Delete(self, node):
911*cda5da8dSAndroid Build Coastguard Worker        self.fill("del ")
912*cda5da8dSAndroid Build Coastguard Worker        self.interleave(lambda: self.write(", "), self.traverse, node.targets)
913*cda5da8dSAndroid Build Coastguard Worker
914*cda5da8dSAndroid Build Coastguard Worker    def visit_Assert(self, node):
915*cda5da8dSAndroid Build Coastguard Worker        self.fill("assert ")
916*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.test)
917*cda5da8dSAndroid Build Coastguard Worker        if node.msg:
918*cda5da8dSAndroid Build Coastguard Worker            self.write(", ")
919*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.msg)
920*cda5da8dSAndroid Build Coastguard Worker
921*cda5da8dSAndroid Build Coastguard Worker    def visit_Global(self, node):
922*cda5da8dSAndroid Build Coastguard Worker        self.fill("global ")
923*cda5da8dSAndroid Build Coastguard Worker        self.interleave(lambda: self.write(", "), self.write, node.names)
924*cda5da8dSAndroid Build Coastguard Worker
925*cda5da8dSAndroid Build Coastguard Worker    def visit_Nonlocal(self, node):
926*cda5da8dSAndroid Build Coastguard Worker        self.fill("nonlocal ")
927*cda5da8dSAndroid Build Coastguard Worker        self.interleave(lambda: self.write(", "), self.write, node.names)
928*cda5da8dSAndroid Build Coastguard Worker
929*cda5da8dSAndroid Build Coastguard Worker    def visit_Await(self, node):
930*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.AWAIT, node):
931*cda5da8dSAndroid Build Coastguard Worker            self.write("await")
932*cda5da8dSAndroid Build Coastguard Worker            if node.value:
933*cda5da8dSAndroid Build Coastguard Worker                self.write(" ")
934*cda5da8dSAndroid Build Coastguard Worker                self.set_precedence(_Precedence.ATOM, node.value)
935*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.value)
936*cda5da8dSAndroid Build Coastguard Worker
937*cda5da8dSAndroid Build Coastguard Worker    def visit_Yield(self, node):
938*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.YIELD, node):
939*cda5da8dSAndroid Build Coastguard Worker            self.write("yield")
940*cda5da8dSAndroid Build Coastguard Worker            if node.value:
941*cda5da8dSAndroid Build Coastguard Worker                self.write(" ")
942*cda5da8dSAndroid Build Coastguard Worker                self.set_precedence(_Precedence.ATOM, node.value)
943*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.value)
944*cda5da8dSAndroid Build Coastguard Worker
945*cda5da8dSAndroid Build Coastguard Worker    def visit_YieldFrom(self, node):
946*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.YIELD, node):
947*cda5da8dSAndroid Build Coastguard Worker            self.write("yield from ")
948*cda5da8dSAndroid Build Coastguard Worker            if not node.value:
949*cda5da8dSAndroid Build Coastguard Worker                raise ValueError("Node can't be used without a value attribute.")
950*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.ATOM, node.value)
951*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.value)
952*cda5da8dSAndroid Build Coastguard Worker
953*cda5da8dSAndroid Build Coastguard Worker    def visit_Raise(self, node):
954*cda5da8dSAndroid Build Coastguard Worker        self.fill("raise")
955*cda5da8dSAndroid Build Coastguard Worker        if not node.exc:
956*cda5da8dSAndroid Build Coastguard Worker            if node.cause:
957*cda5da8dSAndroid Build Coastguard Worker                raise ValueError(f"Node can't use cause without an exception.")
958*cda5da8dSAndroid Build Coastguard Worker            return
959*cda5da8dSAndroid Build Coastguard Worker        self.write(" ")
960*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.exc)
961*cda5da8dSAndroid Build Coastguard Worker        if node.cause:
962*cda5da8dSAndroid Build Coastguard Worker            self.write(" from ")
963*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.cause)
964*cda5da8dSAndroid Build Coastguard Worker
965*cda5da8dSAndroid Build Coastguard Worker    def do_visit_try(self, node):
966*cda5da8dSAndroid Build Coastguard Worker        self.fill("try")
967*cda5da8dSAndroid Build Coastguard Worker        with self.block():
968*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
969*cda5da8dSAndroid Build Coastguard Worker        for ex in node.handlers:
970*cda5da8dSAndroid Build Coastguard Worker            self.traverse(ex)
971*cda5da8dSAndroid Build Coastguard Worker        if node.orelse:
972*cda5da8dSAndroid Build Coastguard Worker            self.fill("else")
973*cda5da8dSAndroid Build Coastguard Worker            with self.block():
974*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.orelse)
975*cda5da8dSAndroid Build Coastguard Worker        if node.finalbody:
976*cda5da8dSAndroid Build Coastguard Worker            self.fill("finally")
977*cda5da8dSAndroid Build Coastguard Worker            with self.block():
978*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.finalbody)
979*cda5da8dSAndroid Build Coastguard Worker
980*cda5da8dSAndroid Build Coastguard Worker    def visit_Try(self, node):
981*cda5da8dSAndroid Build Coastguard Worker        prev_in_try_star = self._in_try_star
982*cda5da8dSAndroid Build Coastguard Worker        try:
983*cda5da8dSAndroid Build Coastguard Worker            self._in_try_star = False
984*cda5da8dSAndroid Build Coastguard Worker            self.do_visit_try(node)
985*cda5da8dSAndroid Build Coastguard Worker        finally:
986*cda5da8dSAndroid Build Coastguard Worker            self._in_try_star = prev_in_try_star
987*cda5da8dSAndroid Build Coastguard Worker
988*cda5da8dSAndroid Build Coastguard Worker    def visit_TryStar(self, node):
989*cda5da8dSAndroid Build Coastguard Worker        prev_in_try_star = self._in_try_star
990*cda5da8dSAndroid Build Coastguard Worker        try:
991*cda5da8dSAndroid Build Coastguard Worker            self._in_try_star = True
992*cda5da8dSAndroid Build Coastguard Worker            self.do_visit_try(node)
993*cda5da8dSAndroid Build Coastguard Worker        finally:
994*cda5da8dSAndroid Build Coastguard Worker            self._in_try_star = prev_in_try_star
995*cda5da8dSAndroid Build Coastguard Worker
996*cda5da8dSAndroid Build Coastguard Worker    def visit_ExceptHandler(self, node):
997*cda5da8dSAndroid Build Coastguard Worker        self.fill("except*" if self._in_try_star else "except")
998*cda5da8dSAndroid Build Coastguard Worker        if node.type:
999*cda5da8dSAndroid Build Coastguard Worker            self.write(" ")
1000*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.type)
1001*cda5da8dSAndroid Build Coastguard Worker        if node.name:
1002*cda5da8dSAndroid Build Coastguard Worker            self.write(" as ")
1003*cda5da8dSAndroid Build Coastguard Worker            self.write(node.name)
1004*cda5da8dSAndroid Build Coastguard Worker        with self.block():
1005*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1006*cda5da8dSAndroid Build Coastguard Worker
1007*cda5da8dSAndroid Build Coastguard Worker    def visit_ClassDef(self, node):
1008*cda5da8dSAndroid Build Coastguard Worker        self.maybe_newline()
1009*cda5da8dSAndroid Build Coastguard Worker        for deco in node.decorator_list:
1010*cda5da8dSAndroid Build Coastguard Worker            self.fill("@")
1011*cda5da8dSAndroid Build Coastguard Worker            self.traverse(deco)
1012*cda5da8dSAndroid Build Coastguard Worker        self.fill("class " + node.name)
1013*cda5da8dSAndroid Build Coastguard Worker        with self.delimit_if("(", ")", condition = node.bases or node.keywords):
1014*cda5da8dSAndroid Build Coastguard Worker            comma = False
1015*cda5da8dSAndroid Build Coastguard Worker            for e in node.bases:
1016*cda5da8dSAndroid Build Coastguard Worker                if comma:
1017*cda5da8dSAndroid Build Coastguard Worker                    self.write(", ")
1018*cda5da8dSAndroid Build Coastguard Worker                else:
1019*cda5da8dSAndroid Build Coastguard Worker                    comma = True
1020*cda5da8dSAndroid Build Coastguard Worker                self.traverse(e)
1021*cda5da8dSAndroid Build Coastguard Worker            for e in node.keywords:
1022*cda5da8dSAndroid Build Coastguard Worker                if comma:
1023*cda5da8dSAndroid Build Coastguard Worker                    self.write(", ")
1024*cda5da8dSAndroid Build Coastguard Worker                else:
1025*cda5da8dSAndroid Build Coastguard Worker                    comma = True
1026*cda5da8dSAndroid Build Coastguard Worker                self.traverse(e)
1027*cda5da8dSAndroid Build Coastguard Worker
1028*cda5da8dSAndroid Build Coastguard Worker        with self.block():
1029*cda5da8dSAndroid Build Coastguard Worker            self._write_docstring_and_traverse_body(node)
1030*cda5da8dSAndroid Build Coastguard Worker
1031*cda5da8dSAndroid Build Coastguard Worker    def visit_FunctionDef(self, node):
1032*cda5da8dSAndroid Build Coastguard Worker        self._function_helper(node, "def")
1033*cda5da8dSAndroid Build Coastguard Worker
1034*cda5da8dSAndroid Build Coastguard Worker    def visit_AsyncFunctionDef(self, node):
1035*cda5da8dSAndroid Build Coastguard Worker        self._function_helper(node, "async def")
1036*cda5da8dSAndroid Build Coastguard Worker
1037*cda5da8dSAndroid Build Coastguard Worker    def _function_helper(self, node, fill_suffix):
1038*cda5da8dSAndroid Build Coastguard Worker        self.maybe_newline()
1039*cda5da8dSAndroid Build Coastguard Worker        for deco in node.decorator_list:
1040*cda5da8dSAndroid Build Coastguard Worker            self.fill("@")
1041*cda5da8dSAndroid Build Coastguard Worker            self.traverse(deco)
1042*cda5da8dSAndroid Build Coastguard Worker        def_str = fill_suffix + " " + node.name
1043*cda5da8dSAndroid Build Coastguard Worker        self.fill(def_str)
1044*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("(", ")"):
1045*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.args)
1046*cda5da8dSAndroid Build Coastguard Worker        if node.returns:
1047*cda5da8dSAndroid Build Coastguard Worker            self.write(" -> ")
1048*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.returns)
1049*cda5da8dSAndroid Build Coastguard Worker        with self.block(extra=self.get_type_comment(node)):
1050*cda5da8dSAndroid Build Coastguard Worker            self._write_docstring_and_traverse_body(node)
1051*cda5da8dSAndroid Build Coastguard Worker
1052*cda5da8dSAndroid Build Coastguard Worker    def visit_For(self, node):
1053*cda5da8dSAndroid Build Coastguard Worker        self._for_helper("for ", node)
1054*cda5da8dSAndroid Build Coastguard Worker
1055*cda5da8dSAndroid Build Coastguard Worker    def visit_AsyncFor(self, node):
1056*cda5da8dSAndroid Build Coastguard Worker        self._for_helper("async for ", node)
1057*cda5da8dSAndroid Build Coastguard Worker
1058*cda5da8dSAndroid Build Coastguard Worker    def _for_helper(self, fill, node):
1059*cda5da8dSAndroid Build Coastguard Worker        self.fill(fill)
1060*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.TUPLE, node.target)
1061*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.target)
1062*cda5da8dSAndroid Build Coastguard Worker        self.write(" in ")
1063*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.iter)
1064*cda5da8dSAndroid Build Coastguard Worker        with self.block(extra=self.get_type_comment(node)):
1065*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1066*cda5da8dSAndroid Build Coastguard Worker        if node.orelse:
1067*cda5da8dSAndroid Build Coastguard Worker            self.fill("else")
1068*cda5da8dSAndroid Build Coastguard Worker            with self.block():
1069*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.orelse)
1070*cda5da8dSAndroid Build Coastguard Worker
1071*cda5da8dSAndroid Build Coastguard Worker    def visit_If(self, node):
1072*cda5da8dSAndroid Build Coastguard Worker        self.fill("if ")
1073*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.test)
1074*cda5da8dSAndroid Build Coastguard Worker        with self.block():
1075*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1076*cda5da8dSAndroid Build Coastguard Worker        # collapse nested ifs into equivalent elifs.
1077*cda5da8dSAndroid Build Coastguard Worker        while node.orelse and len(node.orelse) == 1 and isinstance(node.orelse[0], If):
1078*cda5da8dSAndroid Build Coastguard Worker            node = node.orelse[0]
1079*cda5da8dSAndroid Build Coastguard Worker            self.fill("elif ")
1080*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.test)
1081*cda5da8dSAndroid Build Coastguard Worker            with self.block():
1082*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.body)
1083*cda5da8dSAndroid Build Coastguard Worker        # final else
1084*cda5da8dSAndroid Build Coastguard Worker        if node.orelse:
1085*cda5da8dSAndroid Build Coastguard Worker            self.fill("else")
1086*cda5da8dSAndroid Build Coastguard Worker            with self.block():
1087*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.orelse)
1088*cda5da8dSAndroid Build Coastguard Worker
1089*cda5da8dSAndroid Build Coastguard Worker    def visit_While(self, node):
1090*cda5da8dSAndroid Build Coastguard Worker        self.fill("while ")
1091*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.test)
1092*cda5da8dSAndroid Build Coastguard Worker        with self.block():
1093*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1094*cda5da8dSAndroid Build Coastguard Worker        if node.orelse:
1095*cda5da8dSAndroid Build Coastguard Worker            self.fill("else")
1096*cda5da8dSAndroid Build Coastguard Worker            with self.block():
1097*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.orelse)
1098*cda5da8dSAndroid Build Coastguard Worker
1099*cda5da8dSAndroid Build Coastguard Worker    def visit_With(self, node):
1100*cda5da8dSAndroid Build Coastguard Worker        self.fill("with ")
1101*cda5da8dSAndroid Build Coastguard Worker        self.interleave(lambda: self.write(", "), self.traverse, node.items)
1102*cda5da8dSAndroid Build Coastguard Worker        with self.block(extra=self.get_type_comment(node)):
1103*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1104*cda5da8dSAndroid Build Coastguard Worker
1105*cda5da8dSAndroid Build Coastguard Worker    def visit_AsyncWith(self, node):
1106*cda5da8dSAndroid Build Coastguard Worker        self.fill("async with ")
1107*cda5da8dSAndroid Build Coastguard Worker        self.interleave(lambda: self.write(", "), self.traverse, node.items)
1108*cda5da8dSAndroid Build Coastguard Worker        with self.block(extra=self.get_type_comment(node)):
1109*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1110*cda5da8dSAndroid Build Coastguard Worker
1111*cda5da8dSAndroid Build Coastguard Worker    def _str_literal_helper(
1112*cda5da8dSAndroid Build Coastguard Worker        self, string, *, quote_types=_ALL_QUOTES, escape_special_whitespace=False
1113*cda5da8dSAndroid Build Coastguard Worker    ):
1114*cda5da8dSAndroid Build Coastguard Worker        """Helper for writing string literals, minimizing escapes.
1115*cda5da8dSAndroid Build Coastguard Worker        Returns the tuple (string literal to write, possible quote types).
1116*cda5da8dSAndroid Build Coastguard Worker        """
1117*cda5da8dSAndroid Build Coastguard Worker        def escape_char(c):
1118*cda5da8dSAndroid Build Coastguard Worker            # \n and \t are non-printable, but we only escape them if
1119*cda5da8dSAndroid Build Coastguard Worker            # escape_special_whitespace is True
1120*cda5da8dSAndroid Build Coastguard Worker            if not escape_special_whitespace and c in "\n\t":
1121*cda5da8dSAndroid Build Coastguard Worker                return c
1122*cda5da8dSAndroid Build Coastguard Worker            # Always escape backslashes and other non-printable characters
1123*cda5da8dSAndroid Build Coastguard Worker            if c == "\\" or not c.isprintable():
1124*cda5da8dSAndroid Build Coastguard Worker                return c.encode("unicode_escape").decode("ascii")
1125*cda5da8dSAndroid Build Coastguard Worker            return c
1126*cda5da8dSAndroid Build Coastguard Worker
1127*cda5da8dSAndroid Build Coastguard Worker        escaped_string = "".join(map(escape_char, string))
1128*cda5da8dSAndroid Build Coastguard Worker        possible_quotes = quote_types
1129*cda5da8dSAndroid Build Coastguard Worker        if "\n" in escaped_string:
1130*cda5da8dSAndroid Build Coastguard Worker            possible_quotes = [q for q in possible_quotes if q in _MULTI_QUOTES]
1131*cda5da8dSAndroid Build Coastguard Worker        possible_quotes = [q for q in possible_quotes if q not in escaped_string]
1132*cda5da8dSAndroid Build Coastguard Worker        if not possible_quotes:
1133*cda5da8dSAndroid Build Coastguard Worker            # If there aren't any possible_quotes, fallback to using repr
1134*cda5da8dSAndroid Build Coastguard Worker            # on the original string. Try to use a quote from quote_types,
1135*cda5da8dSAndroid Build Coastguard Worker            # e.g., so that we use triple quotes for docstrings.
1136*cda5da8dSAndroid Build Coastguard Worker            string = repr(string)
1137*cda5da8dSAndroid Build Coastguard Worker            quote = next((q for q in quote_types if string[0] in q), string[0])
1138*cda5da8dSAndroid Build Coastguard Worker            return string[1:-1], [quote]
1139*cda5da8dSAndroid Build Coastguard Worker        if escaped_string:
1140*cda5da8dSAndroid Build Coastguard Worker            # Sort so that we prefer '''"''' over """\""""
1141*cda5da8dSAndroid Build Coastguard Worker            possible_quotes.sort(key=lambda q: q[0] == escaped_string[-1])
1142*cda5da8dSAndroid Build Coastguard Worker            # If we're using triple quotes and we'd need to escape a final
1143*cda5da8dSAndroid Build Coastguard Worker            # quote, escape it
1144*cda5da8dSAndroid Build Coastguard Worker            if possible_quotes[0][0] == escaped_string[-1]:
1145*cda5da8dSAndroid Build Coastguard Worker                assert len(possible_quotes[0]) == 3
1146*cda5da8dSAndroid Build Coastguard Worker                escaped_string = escaped_string[:-1] + "\\" + escaped_string[-1]
1147*cda5da8dSAndroid Build Coastguard Worker        return escaped_string, possible_quotes
1148*cda5da8dSAndroid Build Coastguard Worker
1149*cda5da8dSAndroid Build Coastguard Worker    def _write_str_avoiding_backslashes(self, string, *, quote_types=_ALL_QUOTES):
1150*cda5da8dSAndroid Build Coastguard Worker        """Write string literal value with a best effort attempt to avoid backslashes."""
1151*cda5da8dSAndroid Build Coastguard Worker        string, quote_types = self._str_literal_helper(string, quote_types=quote_types)
1152*cda5da8dSAndroid Build Coastguard Worker        quote_type = quote_types[0]
1153*cda5da8dSAndroid Build Coastguard Worker        self.write(f"{quote_type}{string}{quote_type}")
1154*cda5da8dSAndroid Build Coastguard Worker
1155*cda5da8dSAndroid Build Coastguard Worker    def visit_JoinedStr(self, node):
1156*cda5da8dSAndroid Build Coastguard Worker        self.write("f")
1157*cda5da8dSAndroid Build Coastguard Worker        if self._avoid_backslashes:
1158*cda5da8dSAndroid Build Coastguard Worker            with self.buffered() as buffer:
1159*cda5da8dSAndroid Build Coastguard Worker                self._write_fstring_inner(node)
1160*cda5da8dSAndroid Build Coastguard Worker            return self._write_str_avoiding_backslashes("".join(buffer))
1161*cda5da8dSAndroid Build Coastguard Worker
1162*cda5da8dSAndroid Build Coastguard Worker        # If we don't need to avoid backslashes globally (i.e., we only need
1163*cda5da8dSAndroid Build Coastguard Worker        # to avoid them inside FormattedValues), it's cosmetically preferred
1164*cda5da8dSAndroid Build Coastguard Worker        # to use escaped whitespace. That is, it's preferred to use backslashes
1165*cda5da8dSAndroid Build Coastguard Worker        # for cases like: f"{x}\n". To accomplish this, we keep track of what
1166*cda5da8dSAndroid Build Coastguard Worker        # in our buffer corresponds to FormattedValues and what corresponds to
1167*cda5da8dSAndroid Build Coastguard Worker        # Constant parts of the f-string, and allow escapes accordingly.
1168*cda5da8dSAndroid Build Coastguard Worker        fstring_parts = []
1169*cda5da8dSAndroid Build Coastguard Worker        for value in node.values:
1170*cda5da8dSAndroid Build Coastguard Worker            with self.buffered() as buffer:
1171*cda5da8dSAndroid Build Coastguard Worker                self._write_fstring_inner(value)
1172*cda5da8dSAndroid Build Coastguard Worker            fstring_parts.append(
1173*cda5da8dSAndroid Build Coastguard Worker                ("".join(buffer), isinstance(value, Constant))
1174*cda5da8dSAndroid Build Coastguard Worker            )
1175*cda5da8dSAndroid Build Coastguard Worker
1176*cda5da8dSAndroid Build Coastguard Worker        new_fstring_parts = []
1177*cda5da8dSAndroid Build Coastguard Worker        quote_types = list(_ALL_QUOTES)
1178*cda5da8dSAndroid Build Coastguard Worker        for value, is_constant in fstring_parts:
1179*cda5da8dSAndroid Build Coastguard Worker            value, quote_types = self._str_literal_helper(
1180*cda5da8dSAndroid Build Coastguard Worker                value,
1181*cda5da8dSAndroid Build Coastguard Worker                quote_types=quote_types,
1182*cda5da8dSAndroid Build Coastguard Worker                escape_special_whitespace=is_constant,
1183*cda5da8dSAndroid Build Coastguard Worker            )
1184*cda5da8dSAndroid Build Coastguard Worker            new_fstring_parts.append(value)
1185*cda5da8dSAndroid Build Coastguard Worker
1186*cda5da8dSAndroid Build Coastguard Worker        value = "".join(new_fstring_parts)
1187*cda5da8dSAndroid Build Coastguard Worker        quote_type = quote_types[0]
1188*cda5da8dSAndroid Build Coastguard Worker        self.write(f"{quote_type}{value}{quote_type}")
1189*cda5da8dSAndroid Build Coastguard Worker
1190*cda5da8dSAndroid Build Coastguard Worker    def _write_fstring_inner(self, node):
1191*cda5da8dSAndroid Build Coastguard Worker        if isinstance(node, JoinedStr):
1192*cda5da8dSAndroid Build Coastguard Worker            # for both the f-string itself, and format_spec
1193*cda5da8dSAndroid Build Coastguard Worker            for value in node.values:
1194*cda5da8dSAndroid Build Coastguard Worker                self._write_fstring_inner(value)
1195*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, Constant) and isinstance(node.value, str):
1196*cda5da8dSAndroid Build Coastguard Worker            value = node.value.replace("{", "{{").replace("}", "}}")
1197*cda5da8dSAndroid Build Coastguard Worker            self.write(value)
1198*cda5da8dSAndroid Build Coastguard Worker        elif isinstance(node, FormattedValue):
1199*cda5da8dSAndroid Build Coastguard Worker            self.visit_FormattedValue(node)
1200*cda5da8dSAndroid Build Coastguard Worker        else:
1201*cda5da8dSAndroid Build Coastguard Worker            raise ValueError(f"Unexpected node inside JoinedStr, {node!r}")
1202*cda5da8dSAndroid Build Coastguard Worker
1203*cda5da8dSAndroid Build Coastguard Worker    def visit_FormattedValue(self, node):
1204*cda5da8dSAndroid Build Coastguard Worker        def unparse_inner(inner):
1205*cda5da8dSAndroid Build Coastguard Worker            unparser = type(self)(_avoid_backslashes=True)
1206*cda5da8dSAndroid Build Coastguard Worker            unparser.set_precedence(_Precedence.TEST.next(), inner)
1207*cda5da8dSAndroid Build Coastguard Worker            return unparser.visit(inner)
1208*cda5da8dSAndroid Build Coastguard Worker
1209*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("{", "}"):
1210*cda5da8dSAndroid Build Coastguard Worker            expr = unparse_inner(node.value)
1211*cda5da8dSAndroid Build Coastguard Worker            if "\\" in expr:
1212*cda5da8dSAndroid Build Coastguard Worker                raise ValueError(
1213*cda5da8dSAndroid Build Coastguard Worker                    "Unable to avoid backslash in f-string expression part"
1214*cda5da8dSAndroid Build Coastguard Worker                )
1215*cda5da8dSAndroid Build Coastguard Worker            if expr.startswith("{"):
1216*cda5da8dSAndroid Build Coastguard Worker                # Separate pair of opening brackets as "{ {"
1217*cda5da8dSAndroid Build Coastguard Worker                self.write(" ")
1218*cda5da8dSAndroid Build Coastguard Worker            self.write(expr)
1219*cda5da8dSAndroid Build Coastguard Worker            if node.conversion != -1:
1220*cda5da8dSAndroid Build Coastguard Worker                self.write(f"!{chr(node.conversion)}")
1221*cda5da8dSAndroid Build Coastguard Worker            if node.format_spec:
1222*cda5da8dSAndroid Build Coastguard Worker                self.write(":")
1223*cda5da8dSAndroid Build Coastguard Worker                self._write_fstring_inner(node.format_spec)
1224*cda5da8dSAndroid Build Coastguard Worker
1225*cda5da8dSAndroid Build Coastguard Worker    def visit_Name(self, node):
1226*cda5da8dSAndroid Build Coastguard Worker        self.write(node.id)
1227*cda5da8dSAndroid Build Coastguard Worker
1228*cda5da8dSAndroid Build Coastguard Worker    def _write_docstring(self, node):
1229*cda5da8dSAndroid Build Coastguard Worker        self.fill()
1230*cda5da8dSAndroid Build Coastguard Worker        if node.kind == "u":
1231*cda5da8dSAndroid Build Coastguard Worker            self.write("u")
1232*cda5da8dSAndroid Build Coastguard Worker        self._write_str_avoiding_backslashes(node.value, quote_types=_MULTI_QUOTES)
1233*cda5da8dSAndroid Build Coastguard Worker
1234*cda5da8dSAndroid Build Coastguard Worker    def _write_constant(self, value):
1235*cda5da8dSAndroid Build Coastguard Worker        if isinstance(value, (float, complex)):
1236*cda5da8dSAndroid Build Coastguard Worker            # Substitute overflowing decimal literal for AST infinities,
1237*cda5da8dSAndroid Build Coastguard Worker            # and inf - inf for NaNs.
1238*cda5da8dSAndroid Build Coastguard Worker            self.write(
1239*cda5da8dSAndroid Build Coastguard Worker                repr(value)
1240*cda5da8dSAndroid Build Coastguard Worker                .replace("inf", _INFSTR)
1241*cda5da8dSAndroid Build Coastguard Worker                .replace("nan", f"({_INFSTR}-{_INFSTR})")
1242*cda5da8dSAndroid Build Coastguard Worker            )
1243*cda5da8dSAndroid Build Coastguard Worker        elif self._avoid_backslashes and isinstance(value, str):
1244*cda5da8dSAndroid Build Coastguard Worker            self._write_str_avoiding_backslashes(value)
1245*cda5da8dSAndroid Build Coastguard Worker        else:
1246*cda5da8dSAndroid Build Coastguard Worker            self.write(repr(value))
1247*cda5da8dSAndroid Build Coastguard Worker
1248*cda5da8dSAndroid Build Coastguard Worker    def visit_Constant(self, node):
1249*cda5da8dSAndroid Build Coastguard Worker        value = node.value
1250*cda5da8dSAndroid Build Coastguard Worker        if isinstance(value, tuple):
1251*cda5da8dSAndroid Build Coastguard Worker            with self.delimit("(", ")"):
1252*cda5da8dSAndroid Build Coastguard Worker                self.items_view(self._write_constant, value)
1253*cda5da8dSAndroid Build Coastguard Worker        elif value is ...:
1254*cda5da8dSAndroid Build Coastguard Worker            self.write("...")
1255*cda5da8dSAndroid Build Coastguard Worker        else:
1256*cda5da8dSAndroid Build Coastguard Worker            if node.kind == "u":
1257*cda5da8dSAndroid Build Coastguard Worker                self.write("u")
1258*cda5da8dSAndroid Build Coastguard Worker            self._write_constant(node.value)
1259*cda5da8dSAndroid Build Coastguard Worker
1260*cda5da8dSAndroid Build Coastguard Worker    def visit_List(self, node):
1261*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("[", "]"):
1262*cda5da8dSAndroid Build Coastguard Worker            self.interleave(lambda: self.write(", "), self.traverse, node.elts)
1263*cda5da8dSAndroid Build Coastguard Worker
1264*cda5da8dSAndroid Build Coastguard Worker    def visit_ListComp(self, node):
1265*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("[", "]"):
1266*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.elt)
1267*cda5da8dSAndroid Build Coastguard Worker            for gen in node.generators:
1268*cda5da8dSAndroid Build Coastguard Worker                self.traverse(gen)
1269*cda5da8dSAndroid Build Coastguard Worker
1270*cda5da8dSAndroid Build Coastguard Worker    def visit_GeneratorExp(self, node):
1271*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("(", ")"):
1272*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.elt)
1273*cda5da8dSAndroid Build Coastguard Worker            for gen in node.generators:
1274*cda5da8dSAndroid Build Coastguard Worker                self.traverse(gen)
1275*cda5da8dSAndroid Build Coastguard Worker
1276*cda5da8dSAndroid Build Coastguard Worker    def visit_SetComp(self, node):
1277*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("{", "}"):
1278*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.elt)
1279*cda5da8dSAndroid Build Coastguard Worker            for gen in node.generators:
1280*cda5da8dSAndroid Build Coastguard Worker                self.traverse(gen)
1281*cda5da8dSAndroid Build Coastguard Worker
1282*cda5da8dSAndroid Build Coastguard Worker    def visit_DictComp(self, node):
1283*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("{", "}"):
1284*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.key)
1285*cda5da8dSAndroid Build Coastguard Worker            self.write(": ")
1286*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.value)
1287*cda5da8dSAndroid Build Coastguard Worker            for gen in node.generators:
1288*cda5da8dSAndroid Build Coastguard Worker                self.traverse(gen)
1289*cda5da8dSAndroid Build Coastguard Worker
1290*cda5da8dSAndroid Build Coastguard Worker    def visit_comprehension(self, node):
1291*cda5da8dSAndroid Build Coastguard Worker        if node.is_async:
1292*cda5da8dSAndroid Build Coastguard Worker            self.write(" async for ")
1293*cda5da8dSAndroid Build Coastguard Worker        else:
1294*cda5da8dSAndroid Build Coastguard Worker            self.write(" for ")
1295*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.TUPLE, node.target)
1296*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.target)
1297*cda5da8dSAndroid Build Coastguard Worker        self.write(" in ")
1298*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.TEST.next(), node.iter, *node.ifs)
1299*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.iter)
1300*cda5da8dSAndroid Build Coastguard Worker        for if_clause in node.ifs:
1301*cda5da8dSAndroid Build Coastguard Worker            self.write(" if ")
1302*cda5da8dSAndroid Build Coastguard Worker            self.traverse(if_clause)
1303*cda5da8dSAndroid Build Coastguard Worker
1304*cda5da8dSAndroid Build Coastguard Worker    def visit_IfExp(self, node):
1305*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.TEST, node):
1306*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.TEST.next(), node.body, node.test)
1307*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1308*cda5da8dSAndroid Build Coastguard Worker            self.write(" if ")
1309*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.test)
1310*cda5da8dSAndroid Build Coastguard Worker            self.write(" else ")
1311*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.TEST, node.orelse)
1312*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.orelse)
1313*cda5da8dSAndroid Build Coastguard Worker
1314*cda5da8dSAndroid Build Coastguard Worker    def visit_Set(self, node):
1315*cda5da8dSAndroid Build Coastguard Worker        if node.elts:
1316*cda5da8dSAndroid Build Coastguard Worker            with self.delimit("{", "}"):
1317*cda5da8dSAndroid Build Coastguard Worker                self.interleave(lambda: self.write(", "), self.traverse, node.elts)
1318*cda5da8dSAndroid Build Coastguard Worker        else:
1319*cda5da8dSAndroid Build Coastguard Worker            # `{}` would be interpreted as a dictionary literal, and
1320*cda5da8dSAndroid Build Coastguard Worker            # `set` might be shadowed. Thus:
1321*cda5da8dSAndroid Build Coastguard Worker            self.write('{*()}')
1322*cda5da8dSAndroid Build Coastguard Worker
1323*cda5da8dSAndroid Build Coastguard Worker    def visit_Dict(self, node):
1324*cda5da8dSAndroid Build Coastguard Worker        def write_key_value_pair(k, v):
1325*cda5da8dSAndroid Build Coastguard Worker            self.traverse(k)
1326*cda5da8dSAndroid Build Coastguard Worker            self.write(": ")
1327*cda5da8dSAndroid Build Coastguard Worker            self.traverse(v)
1328*cda5da8dSAndroid Build Coastguard Worker
1329*cda5da8dSAndroid Build Coastguard Worker        def write_item(item):
1330*cda5da8dSAndroid Build Coastguard Worker            k, v = item
1331*cda5da8dSAndroid Build Coastguard Worker            if k is None:
1332*cda5da8dSAndroid Build Coastguard Worker                # for dictionary unpacking operator in dicts {**{'y': 2}}
1333*cda5da8dSAndroid Build Coastguard Worker                # see PEP 448 for details
1334*cda5da8dSAndroid Build Coastguard Worker                self.write("**")
1335*cda5da8dSAndroid Build Coastguard Worker                self.set_precedence(_Precedence.EXPR, v)
1336*cda5da8dSAndroid Build Coastguard Worker                self.traverse(v)
1337*cda5da8dSAndroid Build Coastguard Worker            else:
1338*cda5da8dSAndroid Build Coastguard Worker                write_key_value_pair(k, v)
1339*cda5da8dSAndroid Build Coastguard Worker
1340*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("{", "}"):
1341*cda5da8dSAndroid Build Coastguard Worker            self.interleave(
1342*cda5da8dSAndroid Build Coastguard Worker                lambda: self.write(", "), write_item, zip(node.keys, node.values)
1343*cda5da8dSAndroid Build Coastguard Worker            )
1344*cda5da8dSAndroid Build Coastguard Worker
1345*cda5da8dSAndroid Build Coastguard Worker    def visit_Tuple(self, node):
1346*cda5da8dSAndroid Build Coastguard Worker        with self.delimit_if(
1347*cda5da8dSAndroid Build Coastguard Worker            "(",
1348*cda5da8dSAndroid Build Coastguard Worker            ")",
1349*cda5da8dSAndroid Build Coastguard Worker            len(node.elts) == 0 or self.get_precedence(node) > _Precedence.TUPLE
1350*cda5da8dSAndroid Build Coastguard Worker        ):
1351*cda5da8dSAndroid Build Coastguard Worker            self.items_view(self.traverse, node.elts)
1352*cda5da8dSAndroid Build Coastguard Worker
1353*cda5da8dSAndroid Build Coastguard Worker    unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"}
1354*cda5da8dSAndroid Build Coastguard Worker    unop_precedence = {
1355*cda5da8dSAndroid Build Coastguard Worker        "not": _Precedence.NOT,
1356*cda5da8dSAndroid Build Coastguard Worker        "~": _Precedence.FACTOR,
1357*cda5da8dSAndroid Build Coastguard Worker        "+": _Precedence.FACTOR,
1358*cda5da8dSAndroid Build Coastguard Worker        "-": _Precedence.FACTOR,
1359*cda5da8dSAndroid Build Coastguard Worker    }
1360*cda5da8dSAndroid Build Coastguard Worker
1361*cda5da8dSAndroid Build Coastguard Worker    def visit_UnaryOp(self, node):
1362*cda5da8dSAndroid Build Coastguard Worker        operator = self.unop[node.op.__class__.__name__]
1363*cda5da8dSAndroid Build Coastguard Worker        operator_precedence = self.unop_precedence[operator]
1364*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(operator_precedence, node):
1365*cda5da8dSAndroid Build Coastguard Worker            self.write(operator)
1366*cda5da8dSAndroid Build Coastguard Worker            # factor prefixes (+, -, ~) shouldn't be separated
1367*cda5da8dSAndroid Build Coastguard Worker            # from the value they belong, (e.g: +1 instead of + 1)
1368*cda5da8dSAndroid Build Coastguard Worker            if operator_precedence is not _Precedence.FACTOR:
1369*cda5da8dSAndroid Build Coastguard Worker                self.write(" ")
1370*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(operator_precedence, node.operand)
1371*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.operand)
1372*cda5da8dSAndroid Build Coastguard Worker
1373*cda5da8dSAndroid Build Coastguard Worker    binop = {
1374*cda5da8dSAndroid Build Coastguard Worker        "Add": "+",
1375*cda5da8dSAndroid Build Coastguard Worker        "Sub": "-",
1376*cda5da8dSAndroid Build Coastguard Worker        "Mult": "*",
1377*cda5da8dSAndroid Build Coastguard Worker        "MatMult": "@",
1378*cda5da8dSAndroid Build Coastguard Worker        "Div": "/",
1379*cda5da8dSAndroid Build Coastguard Worker        "Mod": "%",
1380*cda5da8dSAndroid Build Coastguard Worker        "LShift": "<<",
1381*cda5da8dSAndroid Build Coastguard Worker        "RShift": ">>",
1382*cda5da8dSAndroid Build Coastguard Worker        "BitOr": "|",
1383*cda5da8dSAndroid Build Coastguard Worker        "BitXor": "^",
1384*cda5da8dSAndroid Build Coastguard Worker        "BitAnd": "&",
1385*cda5da8dSAndroid Build Coastguard Worker        "FloorDiv": "//",
1386*cda5da8dSAndroid Build Coastguard Worker        "Pow": "**",
1387*cda5da8dSAndroid Build Coastguard Worker    }
1388*cda5da8dSAndroid Build Coastguard Worker
1389*cda5da8dSAndroid Build Coastguard Worker    binop_precedence = {
1390*cda5da8dSAndroid Build Coastguard Worker        "+": _Precedence.ARITH,
1391*cda5da8dSAndroid Build Coastguard Worker        "-": _Precedence.ARITH,
1392*cda5da8dSAndroid Build Coastguard Worker        "*": _Precedence.TERM,
1393*cda5da8dSAndroid Build Coastguard Worker        "@": _Precedence.TERM,
1394*cda5da8dSAndroid Build Coastguard Worker        "/": _Precedence.TERM,
1395*cda5da8dSAndroid Build Coastguard Worker        "%": _Precedence.TERM,
1396*cda5da8dSAndroid Build Coastguard Worker        "<<": _Precedence.SHIFT,
1397*cda5da8dSAndroid Build Coastguard Worker        ">>": _Precedence.SHIFT,
1398*cda5da8dSAndroid Build Coastguard Worker        "|": _Precedence.BOR,
1399*cda5da8dSAndroid Build Coastguard Worker        "^": _Precedence.BXOR,
1400*cda5da8dSAndroid Build Coastguard Worker        "&": _Precedence.BAND,
1401*cda5da8dSAndroid Build Coastguard Worker        "//": _Precedence.TERM,
1402*cda5da8dSAndroid Build Coastguard Worker        "**": _Precedence.POWER,
1403*cda5da8dSAndroid Build Coastguard Worker    }
1404*cda5da8dSAndroid Build Coastguard Worker
1405*cda5da8dSAndroid Build Coastguard Worker    binop_rassoc = frozenset(("**",))
1406*cda5da8dSAndroid Build Coastguard Worker    def visit_BinOp(self, node):
1407*cda5da8dSAndroid Build Coastguard Worker        operator = self.binop[node.op.__class__.__name__]
1408*cda5da8dSAndroid Build Coastguard Worker        operator_precedence = self.binop_precedence[operator]
1409*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(operator_precedence, node):
1410*cda5da8dSAndroid Build Coastguard Worker            if operator in self.binop_rassoc:
1411*cda5da8dSAndroid Build Coastguard Worker                left_precedence = operator_precedence.next()
1412*cda5da8dSAndroid Build Coastguard Worker                right_precedence = operator_precedence
1413*cda5da8dSAndroid Build Coastguard Worker            else:
1414*cda5da8dSAndroid Build Coastguard Worker                left_precedence = operator_precedence
1415*cda5da8dSAndroid Build Coastguard Worker                right_precedence = operator_precedence.next()
1416*cda5da8dSAndroid Build Coastguard Worker
1417*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(left_precedence, node.left)
1418*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.left)
1419*cda5da8dSAndroid Build Coastguard Worker            self.write(f" {operator} ")
1420*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(right_precedence, node.right)
1421*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.right)
1422*cda5da8dSAndroid Build Coastguard Worker
1423*cda5da8dSAndroid Build Coastguard Worker    cmpops = {
1424*cda5da8dSAndroid Build Coastguard Worker        "Eq": "==",
1425*cda5da8dSAndroid Build Coastguard Worker        "NotEq": "!=",
1426*cda5da8dSAndroid Build Coastguard Worker        "Lt": "<",
1427*cda5da8dSAndroid Build Coastguard Worker        "LtE": "<=",
1428*cda5da8dSAndroid Build Coastguard Worker        "Gt": ">",
1429*cda5da8dSAndroid Build Coastguard Worker        "GtE": ">=",
1430*cda5da8dSAndroid Build Coastguard Worker        "Is": "is",
1431*cda5da8dSAndroid Build Coastguard Worker        "IsNot": "is not",
1432*cda5da8dSAndroid Build Coastguard Worker        "In": "in",
1433*cda5da8dSAndroid Build Coastguard Worker        "NotIn": "not in",
1434*cda5da8dSAndroid Build Coastguard Worker    }
1435*cda5da8dSAndroid Build Coastguard Worker
1436*cda5da8dSAndroid Build Coastguard Worker    def visit_Compare(self, node):
1437*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.CMP, node):
1438*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.CMP.next(), node.left, *node.comparators)
1439*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.left)
1440*cda5da8dSAndroid Build Coastguard Worker            for o, e in zip(node.ops, node.comparators):
1441*cda5da8dSAndroid Build Coastguard Worker                self.write(" " + self.cmpops[o.__class__.__name__] + " ")
1442*cda5da8dSAndroid Build Coastguard Worker                self.traverse(e)
1443*cda5da8dSAndroid Build Coastguard Worker
1444*cda5da8dSAndroid Build Coastguard Worker    boolops = {"And": "and", "Or": "or"}
1445*cda5da8dSAndroid Build Coastguard Worker    boolop_precedence = {"and": _Precedence.AND, "or": _Precedence.OR}
1446*cda5da8dSAndroid Build Coastguard Worker
1447*cda5da8dSAndroid Build Coastguard Worker    def visit_BoolOp(self, node):
1448*cda5da8dSAndroid Build Coastguard Worker        operator = self.boolops[node.op.__class__.__name__]
1449*cda5da8dSAndroid Build Coastguard Worker        operator_precedence = self.boolop_precedence[operator]
1450*cda5da8dSAndroid Build Coastguard Worker
1451*cda5da8dSAndroid Build Coastguard Worker        def increasing_level_traverse(node):
1452*cda5da8dSAndroid Build Coastguard Worker            nonlocal operator_precedence
1453*cda5da8dSAndroid Build Coastguard Worker            operator_precedence = operator_precedence.next()
1454*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(operator_precedence, node)
1455*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node)
1456*cda5da8dSAndroid Build Coastguard Worker
1457*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(operator_precedence, node):
1458*cda5da8dSAndroid Build Coastguard Worker            s = f" {operator} "
1459*cda5da8dSAndroid Build Coastguard Worker            self.interleave(lambda: self.write(s), increasing_level_traverse, node.values)
1460*cda5da8dSAndroid Build Coastguard Worker
1461*cda5da8dSAndroid Build Coastguard Worker    def visit_Attribute(self, node):
1462*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.ATOM, node.value)
1463*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
1464*cda5da8dSAndroid Build Coastguard Worker        # Special case: 3.__abs__() is a syntax error, so if node.value
1465*cda5da8dSAndroid Build Coastguard Worker        # is an integer literal then we need to either parenthesize
1466*cda5da8dSAndroid Build Coastguard Worker        # it or add an extra space to get 3 .__abs__().
1467*cda5da8dSAndroid Build Coastguard Worker        if isinstance(node.value, Constant) and isinstance(node.value.value, int):
1468*cda5da8dSAndroid Build Coastguard Worker            self.write(" ")
1469*cda5da8dSAndroid Build Coastguard Worker        self.write(".")
1470*cda5da8dSAndroid Build Coastguard Worker        self.write(node.attr)
1471*cda5da8dSAndroid Build Coastguard Worker
1472*cda5da8dSAndroid Build Coastguard Worker    def visit_Call(self, node):
1473*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.ATOM, node.func)
1474*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.func)
1475*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("(", ")"):
1476*cda5da8dSAndroid Build Coastguard Worker            comma = False
1477*cda5da8dSAndroid Build Coastguard Worker            for e in node.args:
1478*cda5da8dSAndroid Build Coastguard Worker                if comma:
1479*cda5da8dSAndroid Build Coastguard Worker                    self.write(", ")
1480*cda5da8dSAndroid Build Coastguard Worker                else:
1481*cda5da8dSAndroid Build Coastguard Worker                    comma = True
1482*cda5da8dSAndroid Build Coastguard Worker                self.traverse(e)
1483*cda5da8dSAndroid Build Coastguard Worker            for e in node.keywords:
1484*cda5da8dSAndroid Build Coastguard Worker                if comma:
1485*cda5da8dSAndroid Build Coastguard Worker                    self.write(", ")
1486*cda5da8dSAndroid Build Coastguard Worker                else:
1487*cda5da8dSAndroid Build Coastguard Worker                    comma = True
1488*cda5da8dSAndroid Build Coastguard Worker                self.traverse(e)
1489*cda5da8dSAndroid Build Coastguard Worker
1490*cda5da8dSAndroid Build Coastguard Worker    def visit_Subscript(self, node):
1491*cda5da8dSAndroid Build Coastguard Worker        def is_non_empty_tuple(slice_value):
1492*cda5da8dSAndroid Build Coastguard Worker            return (
1493*cda5da8dSAndroid Build Coastguard Worker                isinstance(slice_value, Tuple)
1494*cda5da8dSAndroid Build Coastguard Worker                and slice_value.elts
1495*cda5da8dSAndroid Build Coastguard Worker            )
1496*cda5da8dSAndroid Build Coastguard Worker
1497*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.ATOM, node.value)
1498*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
1499*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("[", "]"):
1500*cda5da8dSAndroid Build Coastguard Worker            if is_non_empty_tuple(node.slice):
1501*cda5da8dSAndroid Build Coastguard Worker                # parentheses can be omitted if the tuple isn't empty
1502*cda5da8dSAndroid Build Coastguard Worker                self.items_view(self.traverse, node.slice.elts)
1503*cda5da8dSAndroid Build Coastguard Worker            else:
1504*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.slice)
1505*cda5da8dSAndroid Build Coastguard Worker
1506*cda5da8dSAndroid Build Coastguard Worker    def visit_Starred(self, node):
1507*cda5da8dSAndroid Build Coastguard Worker        self.write("*")
1508*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.EXPR, node.value)
1509*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
1510*cda5da8dSAndroid Build Coastguard Worker
1511*cda5da8dSAndroid Build Coastguard Worker    def visit_Ellipsis(self, node):
1512*cda5da8dSAndroid Build Coastguard Worker        self.write("...")
1513*cda5da8dSAndroid Build Coastguard Worker
1514*cda5da8dSAndroid Build Coastguard Worker    def visit_Slice(self, node):
1515*cda5da8dSAndroid Build Coastguard Worker        if node.lower:
1516*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.lower)
1517*cda5da8dSAndroid Build Coastguard Worker        self.write(":")
1518*cda5da8dSAndroid Build Coastguard Worker        if node.upper:
1519*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.upper)
1520*cda5da8dSAndroid Build Coastguard Worker        if node.step:
1521*cda5da8dSAndroid Build Coastguard Worker            self.write(":")
1522*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.step)
1523*cda5da8dSAndroid Build Coastguard Worker
1524*cda5da8dSAndroid Build Coastguard Worker    def visit_Match(self, node):
1525*cda5da8dSAndroid Build Coastguard Worker        self.fill("match ")
1526*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.subject)
1527*cda5da8dSAndroid Build Coastguard Worker        with self.block():
1528*cda5da8dSAndroid Build Coastguard Worker            for case in node.cases:
1529*cda5da8dSAndroid Build Coastguard Worker                self.traverse(case)
1530*cda5da8dSAndroid Build Coastguard Worker
1531*cda5da8dSAndroid Build Coastguard Worker    def visit_arg(self, node):
1532*cda5da8dSAndroid Build Coastguard Worker        self.write(node.arg)
1533*cda5da8dSAndroid Build Coastguard Worker        if node.annotation:
1534*cda5da8dSAndroid Build Coastguard Worker            self.write(": ")
1535*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.annotation)
1536*cda5da8dSAndroid Build Coastguard Worker
1537*cda5da8dSAndroid Build Coastguard Worker    def visit_arguments(self, node):
1538*cda5da8dSAndroid Build Coastguard Worker        first = True
1539*cda5da8dSAndroid Build Coastguard Worker        # normal arguments
1540*cda5da8dSAndroid Build Coastguard Worker        all_args = node.posonlyargs + node.args
1541*cda5da8dSAndroid Build Coastguard Worker        defaults = [None] * (len(all_args) - len(node.defaults)) + node.defaults
1542*cda5da8dSAndroid Build Coastguard Worker        for index, elements in enumerate(zip(all_args, defaults), 1):
1543*cda5da8dSAndroid Build Coastguard Worker            a, d = elements
1544*cda5da8dSAndroid Build Coastguard Worker            if first:
1545*cda5da8dSAndroid Build Coastguard Worker                first = False
1546*cda5da8dSAndroid Build Coastguard Worker            else:
1547*cda5da8dSAndroid Build Coastguard Worker                self.write(", ")
1548*cda5da8dSAndroid Build Coastguard Worker            self.traverse(a)
1549*cda5da8dSAndroid Build Coastguard Worker            if d:
1550*cda5da8dSAndroid Build Coastguard Worker                self.write("=")
1551*cda5da8dSAndroid Build Coastguard Worker                self.traverse(d)
1552*cda5da8dSAndroid Build Coastguard Worker            if index == len(node.posonlyargs):
1553*cda5da8dSAndroid Build Coastguard Worker                self.write(", /")
1554*cda5da8dSAndroid Build Coastguard Worker
1555*cda5da8dSAndroid Build Coastguard Worker        # varargs, or bare '*' if no varargs but keyword-only arguments present
1556*cda5da8dSAndroid Build Coastguard Worker        if node.vararg or node.kwonlyargs:
1557*cda5da8dSAndroid Build Coastguard Worker            if first:
1558*cda5da8dSAndroid Build Coastguard Worker                first = False
1559*cda5da8dSAndroid Build Coastguard Worker            else:
1560*cda5da8dSAndroid Build Coastguard Worker                self.write(", ")
1561*cda5da8dSAndroid Build Coastguard Worker            self.write("*")
1562*cda5da8dSAndroid Build Coastguard Worker            if node.vararg:
1563*cda5da8dSAndroid Build Coastguard Worker                self.write(node.vararg.arg)
1564*cda5da8dSAndroid Build Coastguard Worker                if node.vararg.annotation:
1565*cda5da8dSAndroid Build Coastguard Worker                    self.write(": ")
1566*cda5da8dSAndroid Build Coastguard Worker                    self.traverse(node.vararg.annotation)
1567*cda5da8dSAndroid Build Coastguard Worker
1568*cda5da8dSAndroid Build Coastguard Worker        # keyword-only arguments
1569*cda5da8dSAndroid Build Coastguard Worker        if node.kwonlyargs:
1570*cda5da8dSAndroid Build Coastguard Worker            for a, d in zip(node.kwonlyargs, node.kw_defaults):
1571*cda5da8dSAndroid Build Coastguard Worker                self.write(", ")
1572*cda5da8dSAndroid Build Coastguard Worker                self.traverse(a)
1573*cda5da8dSAndroid Build Coastguard Worker                if d:
1574*cda5da8dSAndroid Build Coastguard Worker                    self.write("=")
1575*cda5da8dSAndroid Build Coastguard Worker                    self.traverse(d)
1576*cda5da8dSAndroid Build Coastguard Worker
1577*cda5da8dSAndroid Build Coastguard Worker        # kwargs
1578*cda5da8dSAndroid Build Coastguard Worker        if node.kwarg:
1579*cda5da8dSAndroid Build Coastguard Worker            if first:
1580*cda5da8dSAndroid Build Coastguard Worker                first = False
1581*cda5da8dSAndroid Build Coastguard Worker            else:
1582*cda5da8dSAndroid Build Coastguard Worker                self.write(", ")
1583*cda5da8dSAndroid Build Coastguard Worker            self.write("**" + node.kwarg.arg)
1584*cda5da8dSAndroid Build Coastguard Worker            if node.kwarg.annotation:
1585*cda5da8dSAndroid Build Coastguard Worker                self.write(": ")
1586*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.kwarg.annotation)
1587*cda5da8dSAndroid Build Coastguard Worker
1588*cda5da8dSAndroid Build Coastguard Worker    def visit_keyword(self, node):
1589*cda5da8dSAndroid Build Coastguard Worker        if node.arg is None:
1590*cda5da8dSAndroid Build Coastguard Worker            self.write("**")
1591*cda5da8dSAndroid Build Coastguard Worker        else:
1592*cda5da8dSAndroid Build Coastguard Worker            self.write(node.arg)
1593*cda5da8dSAndroid Build Coastguard Worker            self.write("=")
1594*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
1595*cda5da8dSAndroid Build Coastguard Worker
1596*cda5da8dSAndroid Build Coastguard Worker    def visit_Lambda(self, node):
1597*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.TEST, node):
1598*cda5da8dSAndroid Build Coastguard Worker            self.write("lambda")
1599*cda5da8dSAndroid Build Coastguard Worker            with self.buffered() as buffer:
1600*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.args)
1601*cda5da8dSAndroid Build Coastguard Worker            if buffer:
1602*cda5da8dSAndroid Build Coastguard Worker                self.write(" ", *buffer)
1603*cda5da8dSAndroid Build Coastguard Worker            self.write(": ")
1604*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.TEST, node.body)
1605*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1606*cda5da8dSAndroid Build Coastguard Worker
1607*cda5da8dSAndroid Build Coastguard Worker    def visit_alias(self, node):
1608*cda5da8dSAndroid Build Coastguard Worker        self.write(node.name)
1609*cda5da8dSAndroid Build Coastguard Worker        if node.asname:
1610*cda5da8dSAndroid Build Coastguard Worker            self.write(" as " + node.asname)
1611*cda5da8dSAndroid Build Coastguard Worker
1612*cda5da8dSAndroid Build Coastguard Worker    def visit_withitem(self, node):
1613*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.context_expr)
1614*cda5da8dSAndroid Build Coastguard Worker        if node.optional_vars:
1615*cda5da8dSAndroid Build Coastguard Worker            self.write(" as ")
1616*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.optional_vars)
1617*cda5da8dSAndroid Build Coastguard Worker
1618*cda5da8dSAndroid Build Coastguard Worker    def visit_match_case(self, node):
1619*cda5da8dSAndroid Build Coastguard Worker        self.fill("case ")
1620*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.pattern)
1621*cda5da8dSAndroid Build Coastguard Worker        if node.guard:
1622*cda5da8dSAndroid Build Coastguard Worker            self.write(" if ")
1623*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.guard)
1624*cda5da8dSAndroid Build Coastguard Worker        with self.block():
1625*cda5da8dSAndroid Build Coastguard Worker            self.traverse(node.body)
1626*cda5da8dSAndroid Build Coastguard Worker
1627*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchValue(self, node):
1628*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.value)
1629*cda5da8dSAndroid Build Coastguard Worker
1630*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchSingleton(self, node):
1631*cda5da8dSAndroid Build Coastguard Worker        self._write_constant(node.value)
1632*cda5da8dSAndroid Build Coastguard Worker
1633*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchSequence(self, node):
1634*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("[", "]"):
1635*cda5da8dSAndroid Build Coastguard Worker            self.interleave(
1636*cda5da8dSAndroid Build Coastguard Worker                lambda: self.write(", "), self.traverse, node.patterns
1637*cda5da8dSAndroid Build Coastguard Worker            )
1638*cda5da8dSAndroid Build Coastguard Worker
1639*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchStar(self, node):
1640*cda5da8dSAndroid Build Coastguard Worker        name = node.name
1641*cda5da8dSAndroid Build Coastguard Worker        if name is None:
1642*cda5da8dSAndroid Build Coastguard Worker            name = "_"
1643*cda5da8dSAndroid Build Coastguard Worker        self.write(f"*{name}")
1644*cda5da8dSAndroid Build Coastguard Worker
1645*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchMapping(self, node):
1646*cda5da8dSAndroid Build Coastguard Worker        def write_key_pattern_pair(pair):
1647*cda5da8dSAndroid Build Coastguard Worker            k, p = pair
1648*cda5da8dSAndroid Build Coastguard Worker            self.traverse(k)
1649*cda5da8dSAndroid Build Coastguard Worker            self.write(": ")
1650*cda5da8dSAndroid Build Coastguard Worker            self.traverse(p)
1651*cda5da8dSAndroid Build Coastguard Worker
1652*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("{", "}"):
1653*cda5da8dSAndroid Build Coastguard Worker            keys = node.keys
1654*cda5da8dSAndroid Build Coastguard Worker            self.interleave(
1655*cda5da8dSAndroid Build Coastguard Worker                lambda: self.write(", "),
1656*cda5da8dSAndroid Build Coastguard Worker                write_key_pattern_pair,
1657*cda5da8dSAndroid Build Coastguard Worker                zip(keys, node.patterns, strict=True),
1658*cda5da8dSAndroid Build Coastguard Worker            )
1659*cda5da8dSAndroid Build Coastguard Worker            rest = node.rest
1660*cda5da8dSAndroid Build Coastguard Worker            if rest is not None:
1661*cda5da8dSAndroid Build Coastguard Worker                if keys:
1662*cda5da8dSAndroid Build Coastguard Worker                    self.write(", ")
1663*cda5da8dSAndroid Build Coastguard Worker                self.write(f"**{rest}")
1664*cda5da8dSAndroid Build Coastguard Worker
1665*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchClass(self, node):
1666*cda5da8dSAndroid Build Coastguard Worker        self.set_precedence(_Precedence.ATOM, node.cls)
1667*cda5da8dSAndroid Build Coastguard Worker        self.traverse(node.cls)
1668*cda5da8dSAndroid Build Coastguard Worker        with self.delimit("(", ")"):
1669*cda5da8dSAndroid Build Coastguard Worker            patterns = node.patterns
1670*cda5da8dSAndroid Build Coastguard Worker            self.interleave(
1671*cda5da8dSAndroid Build Coastguard Worker                lambda: self.write(", "), self.traverse, patterns
1672*cda5da8dSAndroid Build Coastguard Worker            )
1673*cda5da8dSAndroid Build Coastguard Worker            attrs = node.kwd_attrs
1674*cda5da8dSAndroid Build Coastguard Worker            if attrs:
1675*cda5da8dSAndroid Build Coastguard Worker                def write_attr_pattern(pair):
1676*cda5da8dSAndroid Build Coastguard Worker                    attr, pattern = pair
1677*cda5da8dSAndroid Build Coastguard Worker                    self.write(f"{attr}=")
1678*cda5da8dSAndroid Build Coastguard Worker                    self.traverse(pattern)
1679*cda5da8dSAndroid Build Coastguard Worker
1680*cda5da8dSAndroid Build Coastguard Worker                if patterns:
1681*cda5da8dSAndroid Build Coastguard Worker                    self.write(", ")
1682*cda5da8dSAndroid Build Coastguard Worker                self.interleave(
1683*cda5da8dSAndroid Build Coastguard Worker                    lambda: self.write(", "),
1684*cda5da8dSAndroid Build Coastguard Worker                    write_attr_pattern,
1685*cda5da8dSAndroid Build Coastguard Worker                    zip(attrs, node.kwd_patterns, strict=True),
1686*cda5da8dSAndroid Build Coastguard Worker                )
1687*cda5da8dSAndroid Build Coastguard Worker
1688*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchAs(self, node):
1689*cda5da8dSAndroid Build Coastguard Worker        name = node.name
1690*cda5da8dSAndroid Build Coastguard Worker        pattern = node.pattern
1691*cda5da8dSAndroid Build Coastguard Worker        if name is None:
1692*cda5da8dSAndroid Build Coastguard Worker            self.write("_")
1693*cda5da8dSAndroid Build Coastguard Worker        elif pattern is None:
1694*cda5da8dSAndroid Build Coastguard Worker            self.write(node.name)
1695*cda5da8dSAndroid Build Coastguard Worker        else:
1696*cda5da8dSAndroid Build Coastguard Worker            with self.require_parens(_Precedence.TEST, node):
1697*cda5da8dSAndroid Build Coastguard Worker                self.set_precedence(_Precedence.BOR, node.pattern)
1698*cda5da8dSAndroid Build Coastguard Worker                self.traverse(node.pattern)
1699*cda5da8dSAndroid Build Coastguard Worker                self.write(f" as {node.name}")
1700*cda5da8dSAndroid Build Coastguard Worker
1701*cda5da8dSAndroid Build Coastguard Worker    def visit_MatchOr(self, node):
1702*cda5da8dSAndroid Build Coastguard Worker        with self.require_parens(_Precedence.BOR, node):
1703*cda5da8dSAndroid Build Coastguard Worker            self.set_precedence(_Precedence.BOR.next(), *node.patterns)
1704*cda5da8dSAndroid Build Coastguard Worker            self.interleave(lambda: self.write(" | "), self.traverse, node.patterns)
1705*cda5da8dSAndroid Build Coastguard Worker
1706*cda5da8dSAndroid Build Coastguard Workerdef unparse(ast_obj):
1707*cda5da8dSAndroid Build Coastguard Worker    unparser = _Unparser()
1708*cda5da8dSAndroid Build Coastguard Worker    return unparser.visit(ast_obj)
1709*cda5da8dSAndroid Build Coastguard Worker
1710*cda5da8dSAndroid Build Coastguard Worker
1711*cda5da8dSAndroid Build Coastguard Workerdef main():
1712*cda5da8dSAndroid Build Coastguard Worker    import argparse
1713*cda5da8dSAndroid Build Coastguard Worker
1714*cda5da8dSAndroid Build Coastguard Worker    parser = argparse.ArgumentParser(prog='python -m ast')
1715*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('infile', type=argparse.FileType(mode='rb'), nargs='?',
1716*cda5da8dSAndroid Build Coastguard Worker                        default='-',
1717*cda5da8dSAndroid Build Coastguard Worker                        help='the file to parse; defaults to stdin')
1718*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('-m', '--mode', default='exec',
1719*cda5da8dSAndroid Build Coastguard Worker                        choices=('exec', 'single', 'eval', 'func_type'),
1720*cda5da8dSAndroid Build Coastguard Worker                        help='specify what kind of code must be parsed')
1721*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('--no-type-comments', default=True, action='store_false',
1722*cda5da8dSAndroid Build Coastguard Worker                        help="don't add information about type comments")
1723*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('-a', '--include-attributes', action='store_true',
1724*cda5da8dSAndroid Build Coastguard Worker                        help='include attributes such as line numbers and '
1725*cda5da8dSAndroid Build Coastguard Worker                             'column offsets')
1726*cda5da8dSAndroid Build Coastguard Worker    parser.add_argument('-i', '--indent', type=int, default=3,
1727*cda5da8dSAndroid Build Coastguard Worker                        help='indentation of nodes (number of spaces)')
1728*cda5da8dSAndroid Build Coastguard Worker    args = parser.parse_args()
1729*cda5da8dSAndroid Build Coastguard Worker
1730*cda5da8dSAndroid Build Coastguard Worker    with args.infile as infile:
1731*cda5da8dSAndroid Build Coastguard Worker        source = infile.read()
1732*cda5da8dSAndroid Build Coastguard Worker    tree = parse(source, args.infile.name, args.mode, type_comments=args.no_type_comments)
1733*cda5da8dSAndroid Build Coastguard Worker    print(dump(tree, include_attributes=args.include_attributes, indent=args.indent))
1734*cda5da8dSAndroid Build Coastguard Worker
1735*cda5da8dSAndroid Build Coastguard Workerif __name__ == '__main__':
1736*cda5da8dSAndroid Build Coastguard Worker    main()
1737