17db96d56Sopenharmony_ci"""
27db96d56Sopenharmony_ci    ast
37db96d56Sopenharmony_ci    ~~~
47db96d56Sopenharmony_ci
57db96d56Sopenharmony_ci    The `ast` module helps Python applications to process trees of the Python
67db96d56Sopenharmony_ci    abstract syntax grammar.  The abstract syntax itself might change with
77db96d56Sopenharmony_ci    each Python release; this module helps to find out programmatically what
87db96d56Sopenharmony_ci    the current grammar looks like and allows modifications of it.
97db96d56Sopenharmony_ci
107db96d56Sopenharmony_ci    An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
117db96d56Sopenharmony_ci    a flag to the `compile()` builtin function or by using the `parse()`
127db96d56Sopenharmony_ci    function from this module.  The result will be a tree of objects whose
137db96d56Sopenharmony_ci    classes all inherit from `ast.AST`.
147db96d56Sopenharmony_ci
157db96d56Sopenharmony_ci    A modified abstract syntax tree can be compiled into a Python code object
167db96d56Sopenharmony_ci    using the built-in `compile()` function.
177db96d56Sopenharmony_ci
187db96d56Sopenharmony_ci    Additionally various helper functions are provided that make working with
197db96d56Sopenharmony_ci    the trees simpler.  The main intention of the helper functions and this
207db96d56Sopenharmony_ci    module in general is to provide an easy to use interface for libraries
217db96d56Sopenharmony_ci    that work tightly with the python syntax (template engines for example).
227db96d56Sopenharmony_ci
237db96d56Sopenharmony_ci
247db96d56Sopenharmony_ci    :copyright: Copyright 2008 by Armin Ronacher.
257db96d56Sopenharmony_ci    :license: Python License.
267db96d56Sopenharmony_ci"""
277db96d56Sopenharmony_ciimport sys
287db96d56Sopenharmony_cifrom _ast import *
297db96d56Sopenharmony_cifrom contextlib import contextmanager, nullcontext
307db96d56Sopenharmony_cifrom enum import IntEnum, auto, _simple_enum
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci
337db96d56Sopenharmony_cidef parse(source, filename='<unknown>', mode='exec', *,
347db96d56Sopenharmony_ci          type_comments=False, feature_version=None):
357db96d56Sopenharmony_ci    """
367db96d56Sopenharmony_ci    Parse the source into an AST node.
377db96d56Sopenharmony_ci    Equivalent to compile(source, filename, mode, PyCF_ONLY_AST).
387db96d56Sopenharmony_ci    Pass type_comments=True to get back type comments where the syntax allows.
397db96d56Sopenharmony_ci    """
407db96d56Sopenharmony_ci    flags = PyCF_ONLY_AST
417db96d56Sopenharmony_ci    if type_comments:
427db96d56Sopenharmony_ci        flags |= PyCF_TYPE_COMMENTS
437db96d56Sopenharmony_ci    if isinstance(feature_version, tuple):
447db96d56Sopenharmony_ci        major, minor = feature_version  # Should be a 2-tuple.
457db96d56Sopenharmony_ci        assert major == 3
467db96d56Sopenharmony_ci        feature_version = minor
477db96d56Sopenharmony_ci    elif feature_version is None:
487db96d56Sopenharmony_ci        feature_version = -1
497db96d56Sopenharmony_ci    # Else it should be an int giving the minor version for 3.x.
507db96d56Sopenharmony_ci    return compile(source, filename, mode, flags,
517db96d56Sopenharmony_ci                   _feature_version=feature_version)
527db96d56Sopenharmony_ci
537db96d56Sopenharmony_ci
547db96d56Sopenharmony_cidef literal_eval(node_or_string):
557db96d56Sopenharmony_ci    """
567db96d56Sopenharmony_ci    Evaluate an expression node or a string containing only a Python
577db96d56Sopenharmony_ci    expression.  The string or node provided may only consist of the following
587db96d56Sopenharmony_ci    Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
597db96d56Sopenharmony_ci    sets, booleans, and None.
607db96d56Sopenharmony_ci
617db96d56Sopenharmony_ci    Caution: A complex expression can overflow the C stack and cause a crash.
627db96d56Sopenharmony_ci    """
637db96d56Sopenharmony_ci    if isinstance(node_or_string, str):
647db96d56Sopenharmony_ci        node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval')
657db96d56Sopenharmony_ci    if isinstance(node_or_string, Expression):
667db96d56Sopenharmony_ci        node_or_string = node_or_string.body
677db96d56Sopenharmony_ci    def _raise_malformed_node(node):
687db96d56Sopenharmony_ci        msg = "malformed node or string"
697db96d56Sopenharmony_ci        if lno := getattr(node, 'lineno', None):
707db96d56Sopenharmony_ci            msg += f' on line {lno}'
717db96d56Sopenharmony_ci        raise ValueError(msg + f': {node!r}')
727db96d56Sopenharmony_ci    def _convert_num(node):
737db96d56Sopenharmony_ci        if not isinstance(node, Constant) or type(node.value) not in (int, float, complex):
747db96d56Sopenharmony_ci            _raise_malformed_node(node)
757db96d56Sopenharmony_ci        return node.value
767db96d56Sopenharmony_ci    def _convert_signed_num(node):
777db96d56Sopenharmony_ci        if isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
787db96d56Sopenharmony_ci            operand = _convert_num(node.operand)
797db96d56Sopenharmony_ci            if isinstance(node.op, UAdd):
807db96d56Sopenharmony_ci                return + operand
817db96d56Sopenharmony_ci            else:
827db96d56Sopenharmony_ci                return - operand
837db96d56Sopenharmony_ci        return _convert_num(node)
847db96d56Sopenharmony_ci    def _convert(node):
857db96d56Sopenharmony_ci        if isinstance(node, Constant):
867db96d56Sopenharmony_ci            return node.value
877db96d56Sopenharmony_ci        elif isinstance(node, Tuple):
887db96d56Sopenharmony_ci            return tuple(map(_convert, node.elts))
897db96d56Sopenharmony_ci        elif isinstance(node, List):
907db96d56Sopenharmony_ci            return list(map(_convert, node.elts))
917db96d56Sopenharmony_ci        elif isinstance(node, Set):
927db96d56Sopenharmony_ci            return set(map(_convert, node.elts))
937db96d56Sopenharmony_ci        elif (isinstance(node, Call) and isinstance(node.func, Name) and
947db96d56Sopenharmony_ci              node.func.id == 'set' and node.args == node.keywords == []):
957db96d56Sopenharmony_ci            return set()
967db96d56Sopenharmony_ci        elif isinstance(node, Dict):
977db96d56Sopenharmony_ci            if len(node.keys) != len(node.values):
987db96d56Sopenharmony_ci                _raise_malformed_node(node)
997db96d56Sopenharmony_ci            return dict(zip(map(_convert, node.keys),
1007db96d56Sopenharmony_ci                            map(_convert, node.values)))
1017db96d56Sopenharmony_ci        elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
1027db96d56Sopenharmony_ci            left = _convert_signed_num(node.left)
1037db96d56Sopenharmony_ci            right = _convert_num(node.right)
1047db96d56Sopenharmony_ci            if isinstance(left, (int, float)) and isinstance(right, complex):
1057db96d56Sopenharmony_ci                if isinstance(node.op, Add):
1067db96d56Sopenharmony_ci                    return left + right
1077db96d56Sopenharmony_ci                else:
1087db96d56Sopenharmony_ci                    return left - right
1097db96d56Sopenharmony_ci        return _convert_signed_num(node)
1107db96d56Sopenharmony_ci    return _convert(node_or_string)
1117db96d56Sopenharmony_ci
1127db96d56Sopenharmony_ci
1137db96d56Sopenharmony_cidef dump(node, annotate_fields=True, include_attributes=False, *, indent=None):
1147db96d56Sopenharmony_ci    """
1157db96d56Sopenharmony_ci    Return a formatted dump of the tree in node.  This is mainly useful for
1167db96d56Sopenharmony_ci    debugging purposes.  If annotate_fields is true (by default),
1177db96d56Sopenharmony_ci    the returned string will show the names and the values for fields.
1187db96d56Sopenharmony_ci    If annotate_fields is false, the result string will be more compact by
1197db96d56Sopenharmony_ci    omitting unambiguous field names.  Attributes such as line
1207db96d56Sopenharmony_ci    numbers and column offsets are not dumped by default.  If this is wanted,
1217db96d56Sopenharmony_ci    include_attributes can be set to true.  If indent is a non-negative
1227db96d56Sopenharmony_ci    integer or string, then the tree will be pretty-printed with that indent
1237db96d56Sopenharmony_ci    level. None (the default) selects the single line representation.
1247db96d56Sopenharmony_ci    """
1257db96d56Sopenharmony_ci    def _format(node, level=0):
1267db96d56Sopenharmony_ci        if indent is not None:
1277db96d56Sopenharmony_ci            level += 1
1287db96d56Sopenharmony_ci            prefix = '\n' + indent * level
1297db96d56Sopenharmony_ci            sep = ',\n' + indent * level
1307db96d56Sopenharmony_ci        else:
1317db96d56Sopenharmony_ci            prefix = ''
1327db96d56Sopenharmony_ci            sep = ', '
1337db96d56Sopenharmony_ci        if isinstance(node, AST):
1347db96d56Sopenharmony_ci            cls = type(node)
1357db96d56Sopenharmony_ci            args = []
1367db96d56Sopenharmony_ci            allsimple = True
1377db96d56Sopenharmony_ci            keywords = annotate_fields
1387db96d56Sopenharmony_ci            for name in node._fields:
1397db96d56Sopenharmony_ci                try:
1407db96d56Sopenharmony_ci                    value = getattr(node, name)
1417db96d56Sopenharmony_ci                except AttributeError:
1427db96d56Sopenharmony_ci                    keywords = True
1437db96d56Sopenharmony_ci                    continue
1447db96d56Sopenharmony_ci                if value is None and getattr(cls, name, ...) is None:
1457db96d56Sopenharmony_ci                    keywords = True
1467db96d56Sopenharmony_ci                    continue
1477db96d56Sopenharmony_ci                value, simple = _format(value, level)
1487db96d56Sopenharmony_ci                allsimple = allsimple and simple
1497db96d56Sopenharmony_ci                if keywords:
1507db96d56Sopenharmony_ci                    args.append('%s=%s' % (name, value))
1517db96d56Sopenharmony_ci                else:
1527db96d56Sopenharmony_ci                    args.append(value)
1537db96d56Sopenharmony_ci            if include_attributes and node._attributes:
1547db96d56Sopenharmony_ci                for name in node._attributes:
1557db96d56Sopenharmony_ci                    try:
1567db96d56Sopenharmony_ci                        value = getattr(node, name)
1577db96d56Sopenharmony_ci                    except AttributeError:
1587db96d56Sopenharmony_ci                        continue
1597db96d56Sopenharmony_ci                    if value is None and getattr(cls, name, ...) is None:
1607db96d56Sopenharmony_ci                        continue
1617db96d56Sopenharmony_ci                    value, simple = _format(value, level)
1627db96d56Sopenharmony_ci                    allsimple = allsimple and simple
1637db96d56Sopenharmony_ci                    args.append('%s=%s' % (name, value))
1647db96d56Sopenharmony_ci            if allsimple and len(args) <= 3:
1657db96d56Sopenharmony_ci                return '%s(%s)' % (node.__class__.__name__, ', '.join(args)), not args
1667db96d56Sopenharmony_ci            return '%s(%s%s)' % (node.__class__.__name__, prefix, sep.join(args)), False
1677db96d56Sopenharmony_ci        elif isinstance(node, list):
1687db96d56Sopenharmony_ci            if not node:
1697db96d56Sopenharmony_ci                return '[]', True
1707db96d56Sopenharmony_ci            return '[%s%s]' % (prefix, sep.join(_format(x, level)[0] for x in node)), False
1717db96d56Sopenharmony_ci        return repr(node), True
1727db96d56Sopenharmony_ci
1737db96d56Sopenharmony_ci    if not isinstance(node, AST):
1747db96d56Sopenharmony_ci        raise TypeError('expected AST, got %r' % node.__class__.__name__)
1757db96d56Sopenharmony_ci    if indent is not None and not isinstance(indent, str):
1767db96d56Sopenharmony_ci        indent = ' ' * indent
1777db96d56Sopenharmony_ci    return _format(node)[0]
1787db96d56Sopenharmony_ci
1797db96d56Sopenharmony_ci
1807db96d56Sopenharmony_cidef copy_location(new_node, old_node):
1817db96d56Sopenharmony_ci    """
1827db96d56Sopenharmony_ci    Copy source location (`lineno`, `col_offset`, `end_lineno`, and `end_col_offset`
1837db96d56Sopenharmony_ci    attributes) from *old_node* to *new_node* if possible, and return *new_node*.
1847db96d56Sopenharmony_ci    """
1857db96d56Sopenharmony_ci    for attr in 'lineno', 'col_offset', 'end_lineno', 'end_col_offset':
1867db96d56Sopenharmony_ci        if attr in old_node._attributes and attr in new_node._attributes:
1877db96d56Sopenharmony_ci            value = getattr(old_node, attr, None)
1887db96d56Sopenharmony_ci            # end_lineno and end_col_offset are optional attributes, and they
1897db96d56Sopenharmony_ci            # should be copied whether the value is None or not.
1907db96d56Sopenharmony_ci            if value is not None or (
1917db96d56Sopenharmony_ci                hasattr(old_node, attr) and attr.startswith("end_")
1927db96d56Sopenharmony_ci            ):
1937db96d56Sopenharmony_ci                setattr(new_node, attr, value)
1947db96d56Sopenharmony_ci    return new_node
1957db96d56Sopenharmony_ci
1967db96d56Sopenharmony_ci
1977db96d56Sopenharmony_cidef fix_missing_locations(node):
1987db96d56Sopenharmony_ci    """
1997db96d56Sopenharmony_ci    When you compile a node tree with compile(), the compiler expects lineno and
2007db96d56Sopenharmony_ci    col_offset attributes for every node that supports them.  This is rather
2017db96d56Sopenharmony_ci    tedious to fill in for generated nodes, so this helper adds these attributes
2027db96d56Sopenharmony_ci    recursively where not already set, by setting them to the values of the
2037db96d56Sopenharmony_ci    parent node.  It works recursively starting at *node*.
2047db96d56Sopenharmony_ci    """
2057db96d56Sopenharmony_ci    def _fix(node, lineno, col_offset, end_lineno, end_col_offset):
2067db96d56Sopenharmony_ci        if 'lineno' in node._attributes:
2077db96d56Sopenharmony_ci            if not hasattr(node, 'lineno'):
2087db96d56Sopenharmony_ci                node.lineno = lineno
2097db96d56Sopenharmony_ci            else:
2107db96d56Sopenharmony_ci                lineno = node.lineno
2117db96d56Sopenharmony_ci        if 'end_lineno' in node._attributes:
2127db96d56Sopenharmony_ci            if getattr(node, 'end_lineno', None) is None:
2137db96d56Sopenharmony_ci                node.end_lineno = end_lineno
2147db96d56Sopenharmony_ci            else:
2157db96d56Sopenharmony_ci                end_lineno = node.end_lineno
2167db96d56Sopenharmony_ci        if 'col_offset' in node._attributes:
2177db96d56Sopenharmony_ci            if not hasattr(node, 'col_offset'):
2187db96d56Sopenharmony_ci                node.col_offset = col_offset
2197db96d56Sopenharmony_ci            else:
2207db96d56Sopenharmony_ci                col_offset = node.col_offset
2217db96d56Sopenharmony_ci        if 'end_col_offset' in node._attributes:
2227db96d56Sopenharmony_ci            if getattr(node, 'end_col_offset', None) is None:
2237db96d56Sopenharmony_ci                node.end_col_offset = end_col_offset
2247db96d56Sopenharmony_ci            else:
2257db96d56Sopenharmony_ci                end_col_offset = node.end_col_offset
2267db96d56Sopenharmony_ci        for child in iter_child_nodes(node):
2277db96d56Sopenharmony_ci            _fix(child, lineno, col_offset, end_lineno, end_col_offset)
2287db96d56Sopenharmony_ci    _fix(node, 1, 0, 1, 0)
2297db96d56Sopenharmony_ci    return node
2307db96d56Sopenharmony_ci
2317db96d56Sopenharmony_ci
2327db96d56Sopenharmony_cidef increment_lineno(node, n=1):
2337db96d56Sopenharmony_ci    """
2347db96d56Sopenharmony_ci    Increment the line number and end line number of each node in the tree
2357db96d56Sopenharmony_ci    starting at *node* by *n*. This is useful to "move code" to a different
2367db96d56Sopenharmony_ci    location in a file.
2377db96d56Sopenharmony_ci    """
2387db96d56Sopenharmony_ci    for child in walk(node):
2397db96d56Sopenharmony_ci        # TypeIgnore is a special case where lineno is not an attribute
2407db96d56Sopenharmony_ci        # but rather a field of the node itself.
2417db96d56Sopenharmony_ci        if isinstance(child, TypeIgnore):
2427db96d56Sopenharmony_ci            child.lineno = getattr(child, 'lineno', 0) + n
2437db96d56Sopenharmony_ci            continue
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci        if 'lineno' in child._attributes:
2467db96d56Sopenharmony_ci            child.lineno = getattr(child, 'lineno', 0) + n
2477db96d56Sopenharmony_ci        if (
2487db96d56Sopenharmony_ci            "end_lineno" in child._attributes
2497db96d56Sopenharmony_ci            and (end_lineno := getattr(child, "end_lineno", 0)) is not None
2507db96d56Sopenharmony_ci        ):
2517db96d56Sopenharmony_ci            child.end_lineno = end_lineno + n
2527db96d56Sopenharmony_ci    return node
2537db96d56Sopenharmony_ci
2547db96d56Sopenharmony_ci
2557db96d56Sopenharmony_cidef iter_fields(node):
2567db96d56Sopenharmony_ci    """
2577db96d56Sopenharmony_ci    Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
2587db96d56Sopenharmony_ci    that is present on *node*.
2597db96d56Sopenharmony_ci    """
2607db96d56Sopenharmony_ci    for field in node._fields:
2617db96d56Sopenharmony_ci        try:
2627db96d56Sopenharmony_ci            yield field, getattr(node, field)
2637db96d56Sopenharmony_ci        except AttributeError:
2647db96d56Sopenharmony_ci            pass
2657db96d56Sopenharmony_ci
2667db96d56Sopenharmony_ci
2677db96d56Sopenharmony_cidef iter_child_nodes(node):
2687db96d56Sopenharmony_ci    """
2697db96d56Sopenharmony_ci    Yield all direct child nodes of *node*, that is, all fields that are nodes
2707db96d56Sopenharmony_ci    and all items of fields that are lists of nodes.
2717db96d56Sopenharmony_ci    """
2727db96d56Sopenharmony_ci    for name, field in iter_fields(node):
2737db96d56Sopenharmony_ci        if isinstance(field, AST):
2747db96d56Sopenharmony_ci            yield field
2757db96d56Sopenharmony_ci        elif isinstance(field, list):
2767db96d56Sopenharmony_ci            for item in field:
2777db96d56Sopenharmony_ci                if isinstance(item, AST):
2787db96d56Sopenharmony_ci                    yield item
2797db96d56Sopenharmony_ci
2807db96d56Sopenharmony_ci
2817db96d56Sopenharmony_cidef get_docstring(node, clean=True):
2827db96d56Sopenharmony_ci    """
2837db96d56Sopenharmony_ci    Return the docstring for the given node or None if no docstring can
2847db96d56Sopenharmony_ci    be found.  If the node provided does not have docstrings a TypeError
2857db96d56Sopenharmony_ci    will be raised.
2867db96d56Sopenharmony_ci
2877db96d56Sopenharmony_ci    If *clean* is `True`, all tabs are expanded to spaces and any whitespace
2887db96d56Sopenharmony_ci    that can be uniformly removed from the second line onwards is removed.
2897db96d56Sopenharmony_ci    """
2907db96d56Sopenharmony_ci    if not isinstance(node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)):
2917db96d56Sopenharmony_ci        raise TypeError("%r can't have docstrings" % node.__class__.__name__)
2927db96d56Sopenharmony_ci    if not(node.body and isinstance(node.body[0], Expr)):
2937db96d56Sopenharmony_ci        return None
2947db96d56Sopenharmony_ci    node = node.body[0].value
2957db96d56Sopenharmony_ci    if isinstance(node, Str):
2967db96d56Sopenharmony_ci        text = node.s
2977db96d56Sopenharmony_ci    elif isinstance(node, Constant) and isinstance(node.value, str):
2987db96d56Sopenharmony_ci        text = node.value
2997db96d56Sopenharmony_ci    else:
3007db96d56Sopenharmony_ci        return None
3017db96d56Sopenharmony_ci    if clean:
3027db96d56Sopenharmony_ci        import inspect
3037db96d56Sopenharmony_ci        text = inspect.cleandoc(text)
3047db96d56Sopenharmony_ci    return text
3057db96d56Sopenharmony_ci
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_cidef _splitlines_no_ff(source):
3087db96d56Sopenharmony_ci    """Split a string into lines ignoring form feed and other chars.
3097db96d56Sopenharmony_ci
3107db96d56Sopenharmony_ci    This mimics how the Python parser splits source code.
3117db96d56Sopenharmony_ci    """
3127db96d56Sopenharmony_ci    idx = 0
3137db96d56Sopenharmony_ci    lines = []
3147db96d56Sopenharmony_ci    next_line = ''
3157db96d56Sopenharmony_ci    while idx < len(source):
3167db96d56Sopenharmony_ci        c = source[idx]
3177db96d56Sopenharmony_ci        next_line += c
3187db96d56Sopenharmony_ci        idx += 1
3197db96d56Sopenharmony_ci        # Keep \r\n together
3207db96d56Sopenharmony_ci        if c == '\r' and idx < len(source) and source[idx] == '\n':
3217db96d56Sopenharmony_ci            next_line += '\n'
3227db96d56Sopenharmony_ci            idx += 1
3237db96d56Sopenharmony_ci        if c in '\r\n':
3247db96d56Sopenharmony_ci            lines.append(next_line)
3257db96d56Sopenharmony_ci            next_line = ''
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ci    if next_line:
3287db96d56Sopenharmony_ci        lines.append(next_line)
3297db96d56Sopenharmony_ci    return lines
3307db96d56Sopenharmony_ci
3317db96d56Sopenharmony_ci
3327db96d56Sopenharmony_cidef _pad_whitespace(source):
3337db96d56Sopenharmony_ci    r"""Replace all chars except '\f\t' in a line with spaces."""
3347db96d56Sopenharmony_ci    result = ''
3357db96d56Sopenharmony_ci    for c in source:
3367db96d56Sopenharmony_ci        if c in '\f\t':
3377db96d56Sopenharmony_ci            result += c
3387db96d56Sopenharmony_ci        else:
3397db96d56Sopenharmony_ci            result += ' '
3407db96d56Sopenharmony_ci    return result
3417db96d56Sopenharmony_ci
3427db96d56Sopenharmony_ci
3437db96d56Sopenharmony_cidef get_source_segment(source, node, *, padded=False):
3447db96d56Sopenharmony_ci    """Get source code segment of the *source* that generated *node*.
3457db96d56Sopenharmony_ci
3467db96d56Sopenharmony_ci    If some location information (`lineno`, `end_lineno`, `col_offset`,
3477db96d56Sopenharmony_ci    or `end_col_offset`) is missing, return None.
3487db96d56Sopenharmony_ci
3497db96d56Sopenharmony_ci    If *padded* is `True`, the first line of a multi-line statement will
3507db96d56Sopenharmony_ci    be padded with spaces to match its original position.
3517db96d56Sopenharmony_ci    """
3527db96d56Sopenharmony_ci    try:
3537db96d56Sopenharmony_ci        if node.end_lineno is None or node.end_col_offset is None:
3547db96d56Sopenharmony_ci            return None
3557db96d56Sopenharmony_ci        lineno = node.lineno - 1
3567db96d56Sopenharmony_ci        end_lineno = node.end_lineno - 1
3577db96d56Sopenharmony_ci        col_offset = node.col_offset
3587db96d56Sopenharmony_ci        end_col_offset = node.end_col_offset
3597db96d56Sopenharmony_ci    except AttributeError:
3607db96d56Sopenharmony_ci        return None
3617db96d56Sopenharmony_ci
3627db96d56Sopenharmony_ci    lines = _splitlines_no_ff(source)
3637db96d56Sopenharmony_ci    if end_lineno == lineno:
3647db96d56Sopenharmony_ci        return lines[lineno].encode()[col_offset:end_col_offset].decode()
3657db96d56Sopenharmony_ci
3667db96d56Sopenharmony_ci    if padded:
3677db96d56Sopenharmony_ci        padding = _pad_whitespace(lines[lineno].encode()[:col_offset].decode())
3687db96d56Sopenharmony_ci    else:
3697db96d56Sopenharmony_ci        padding = ''
3707db96d56Sopenharmony_ci
3717db96d56Sopenharmony_ci    first = padding + lines[lineno].encode()[col_offset:].decode()
3727db96d56Sopenharmony_ci    last = lines[end_lineno].encode()[:end_col_offset].decode()
3737db96d56Sopenharmony_ci    lines = lines[lineno+1:end_lineno]
3747db96d56Sopenharmony_ci
3757db96d56Sopenharmony_ci    lines.insert(0, first)
3767db96d56Sopenharmony_ci    lines.append(last)
3777db96d56Sopenharmony_ci    return ''.join(lines)
3787db96d56Sopenharmony_ci
3797db96d56Sopenharmony_ci
3807db96d56Sopenharmony_cidef walk(node):
3817db96d56Sopenharmony_ci    """
3827db96d56Sopenharmony_ci    Recursively yield all descendant nodes in the tree starting at *node*
3837db96d56Sopenharmony_ci    (including *node* itself), in no specified order.  This is useful if you
3847db96d56Sopenharmony_ci    only want to modify nodes in place and don't care about the context.
3857db96d56Sopenharmony_ci    """
3867db96d56Sopenharmony_ci    from collections import deque
3877db96d56Sopenharmony_ci    todo = deque([node])
3887db96d56Sopenharmony_ci    while todo:
3897db96d56Sopenharmony_ci        node = todo.popleft()
3907db96d56Sopenharmony_ci        todo.extend(iter_child_nodes(node))
3917db96d56Sopenharmony_ci        yield node
3927db96d56Sopenharmony_ci
3937db96d56Sopenharmony_ci
3947db96d56Sopenharmony_ciclass NodeVisitor(object):
3957db96d56Sopenharmony_ci    """
3967db96d56Sopenharmony_ci    A node visitor base class that walks the abstract syntax tree and calls a
3977db96d56Sopenharmony_ci    visitor function for every node found.  This function may return a value
3987db96d56Sopenharmony_ci    which is forwarded by the `visit` method.
3997db96d56Sopenharmony_ci
4007db96d56Sopenharmony_ci    This class is meant to be subclassed, with the subclass adding visitor
4017db96d56Sopenharmony_ci    methods.
4027db96d56Sopenharmony_ci
4037db96d56Sopenharmony_ci    Per default the visitor functions for the nodes are ``'visit_'`` +
4047db96d56Sopenharmony_ci    class name of the node.  So a `TryFinally` node visit function would
4057db96d56Sopenharmony_ci    be `visit_TryFinally`.  This behavior can be changed by overriding
4067db96d56Sopenharmony_ci    the `visit` method.  If no visitor function exists for a node
4077db96d56Sopenharmony_ci    (return value `None`) the `generic_visit` visitor is used instead.
4087db96d56Sopenharmony_ci
4097db96d56Sopenharmony_ci    Don't use the `NodeVisitor` if you want to apply changes to nodes during
4107db96d56Sopenharmony_ci    traversing.  For this a special visitor exists (`NodeTransformer`) that
4117db96d56Sopenharmony_ci    allows modifications.
4127db96d56Sopenharmony_ci    """
4137db96d56Sopenharmony_ci
4147db96d56Sopenharmony_ci    def visit(self, node):
4157db96d56Sopenharmony_ci        """Visit a node."""
4167db96d56Sopenharmony_ci        method = 'visit_' + node.__class__.__name__
4177db96d56Sopenharmony_ci        visitor = getattr(self, method, self.generic_visit)
4187db96d56Sopenharmony_ci        return visitor(node)
4197db96d56Sopenharmony_ci
4207db96d56Sopenharmony_ci    def generic_visit(self, node):
4217db96d56Sopenharmony_ci        """Called if no explicit visitor function exists for a node."""
4227db96d56Sopenharmony_ci        for field, value in iter_fields(node):
4237db96d56Sopenharmony_ci            if isinstance(value, list):
4247db96d56Sopenharmony_ci                for item in value:
4257db96d56Sopenharmony_ci                    if isinstance(item, AST):
4267db96d56Sopenharmony_ci                        self.visit(item)
4277db96d56Sopenharmony_ci            elif isinstance(value, AST):
4287db96d56Sopenharmony_ci                self.visit(value)
4297db96d56Sopenharmony_ci
4307db96d56Sopenharmony_ci    def visit_Constant(self, node):
4317db96d56Sopenharmony_ci        value = node.value
4327db96d56Sopenharmony_ci        type_name = _const_node_type_names.get(type(value))
4337db96d56Sopenharmony_ci        if type_name is None:
4347db96d56Sopenharmony_ci            for cls, name in _const_node_type_names.items():
4357db96d56Sopenharmony_ci                if isinstance(value, cls):
4367db96d56Sopenharmony_ci                    type_name = name
4377db96d56Sopenharmony_ci                    break
4387db96d56Sopenharmony_ci        if type_name is not None:
4397db96d56Sopenharmony_ci            method = 'visit_' + type_name
4407db96d56Sopenharmony_ci            try:
4417db96d56Sopenharmony_ci                visitor = getattr(self, method)
4427db96d56Sopenharmony_ci            except AttributeError:
4437db96d56Sopenharmony_ci                pass
4447db96d56Sopenharmony_ci            else:
4457db96d56Sopenharmony_ci                import warnings
4467db96d56Sopenharmony_ci                warnings.warn(f"{method} is deprecated; add visit_Constant",
4477db96d56Sopenharmony_ci                              DeprecationWarning, 2)
4487db96d56Sopenharmony_ci                return visitor(node)
4497db96d56Sopenharmony_ci        return self.generic_visit(node)
4507db96d56Sopenharmony_ci
4517db96d56Sopenharmony_ci
4527db96d56Sopenharmony_ciclass NodeTransformer(NodeVisitor):
4537db96d56Sopenharmony_ci    """
4547db96d56Sopenharmony_ci    A :class:`NodeVisitor` subclass that walks the abstract syntax tree and
4557db96d56Sopenharmony_ci    allows modification of nodes.
4567db96d56Sopenharmony_ci
4577db96d56Sopenharmony_ci    The `NodeTransformer` will walk the AST and use the return value of the
4587db96d56Sopenharmony_ci    visitor methods to replace or remove the old node.  If the return value of
4597db96d56Sopenharmony_ci    the visitor method is ``None``, the node will be removed from its location,
4607db96d56Sopenharmony_ci    otherwise it is replaced with the return value.  The return value may be the
4617db96d56Sopenharmony_ci    original node in which case no replacement takes place.
4627db96d56Sopenharmony_ci
4637db96d56Sopenharmony_ci    Here is an example transformer that rewrites all occurrences of name lookups
4647db96d56Sopenharmony_ci    (``foo``) to ``data['foo']``::
4657db96d56Sopenharmony_ci
4667db96d56Sopenharmony_ci       class RewriteName(NodeTransformer):
4677db96d56Sopenharmony_ci
4687db96d56Sopenharmony_ci           def visit_Name(self, node):
4697db96d56Sopenharmony_ci               return Subscript(
4707db96d56Sopenharmony_ci                   value=Name(id='data', ctx=Load()),
4717db96d56Sopenharmony_ci                   slice=Constant(value=node.id),
4727db96d56Sopenharmony_ci                   ctx=node.ctx
4737db96d56Sopenharmony_ci               )
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci    Keep in mind that if the node you're operating on has child nodes you must
4767db96d56Sopenharmony_ci    either transform the child nodes yourself or call the :meth:`generic_visit`
4777db96d56Sopenharmony_ci    method for the node first.
4787db96d56Sopenharmony_ci
4797db96d56Sopenharmony_ci    For nodes that were part of a collection of statements (that applies to all
4807db96d56Sopenharmony_ci    statement nodes), the visitor may also return a list of nodes rather than
4817db96d56Sopenharmony_ci    just a single node.
4827db96d56Sopenharmony_ci
4837db96d56Sopenharmony_ci    Usually you use the transformer like this::
4847db96d56Sopenharmony_ci
4857db96d56Sopenharmony_ci       node = YourTransformer().visit(node)
4867db96d56Sopenharmony_ci    """
4877db96d56Sopenharmony_ci
4887db96d56Sopenharmony_ci    def generic_visit(self, node):
4897db96d56Sopenharmony_ci        for field, old_value in iter_fields(node):
4907db96d56Sopenharmony_ci            if isinstance(old_value, list):
4917db96d56Sopenharmony_ci                new_values = []
4927db96d56Sopenharmony_ci                for value in old_value:
4937db96d56Sopenharmony_ci                    if isinstance(value, AST):
4947db96d56Sopenharmony_ci                        value = self.visit(value)
4957db96d56Sopenharmony_ci                        if value is None:
4967db96d56Sopenharmony_ci                            continue
4977db96d56Sopenharmony_ci                        elif not isinstance(value, AST):
4987db96d56Sopenharmony_ci                            new_values.extend(value)
4997db96d56Sopenharmony_ci                            continue
5007db96d56Sopenharmony_ci                    new_values.append(value)
5017db96d56Sopenharmony_ci                old_value[:] = new_values
5027db96d56Sopenharmony_ci            elif isinstance(old_value, AST):
5037db96d56Sopenharmony_ci                new_node = self.visit(old_value)
5047db96d56Sopenharmony_ci                if new_node is None:
5057db96d56Sopenharmony_ci                    delattr(node, field)
5067db96d56Sopenharmony_ci                else:
5077db96d56Sopenharmony_ci                    setattr(node, field, new_node)
5087db96d56Sopenharmony_ci        return node
5097db96d56Sopenharmony_ci
5107db96d56Sopenharmony_ci
5117db96d56Sopenharmony_ci# If the ast module is loaded more than once, only add deprecated methods once
5127db96d56Sopenharmony_ciif not hasattr(Constant, 'n'):
5137db96d56Sopenharmony_ci    # The following code is for backward compatibility.
5147db96d56Sopenharmony_ci    # It will be removed in future.
5157db96d56Sopenharmony_ci
5167db96d56Sopenharmony_ci    def _getter(self):
5177db96d56Sopenharmony_ci        """Deprecated. Use value instead."""
5187db96d56Sopenharmony_ci        return self.value
5197db96d56Sopenharmony_ci
5207db96d56Sopenharmony_ci    def _setter(self, value):
5217db96d56Sopenharmony_ci        self.value = value
5227db96d56Sopenharmony_ci
5237db96d56Sopenharmony_ci    Constant.n = property(_getter, _setter)
5247db96d56Sopenharmony_ci    Constant.s = property(_getter, _setter)
5257db96d56Sopenharmony_ci
5267db96d56Sopenharmony_ciclass _ABC(type):
5277db96d56Sopenharmony_ci
5287db96d56Sopenharmony_ci    def __init__(cls, *args):
5297db96d56Sopenharmony_ci        cls.__doc__ = """Deprecated AST node class. Use ast.Constant instead"""
5307db96d56Sopenharmony_ci
5317db96d56Sopenharmony_ci    def __instancecheck__(cls, inst):
5327db96d56Sopenharmony_ci        if not isinstance(inst, Constant):
5337db96d56Sopenharmony_ci            return False
5347db96d56Sopenharmony_ci        if cls in _const_types:
5357db96d56Sopenharmony_ci            try:
5367db96d56Sopenharmony_ci                value = inst.value
5377db96d56Sopenharmony_ci            except AttributeError:
5387db96d56Sopenharmony_ci                return False
5397db96d56Sopenharmony_ci            else:
5407db96d56Sopenharmony_ci                return (
5417db96d56Sopenharmony_ci                    isinstance(value, _const_types[cls]) and
5427db96d56Sopenharmony_ci                    not isinstance(value, _const_types_not.get(cls, ()))
5437db96d56Sopenharmony_ci                )
5447db96d56Sopenharmony_ci        return type.__instancecheck__(cls, inst)
5457db96d56Sopenharmony_ci
5467db96d56Sopenharmony_cidef _new(cls, *args, **kwargs):
5477db96d56Sopenharmony_ci    for key in kwargs:
5487db96d56Sopenharmony_ci        if key not in cls._fields:
5497db96d56Sopenharmony_ci            # arbitrary keyword arguments are accepted
5507db96d56Sopenharmony_ci            continue
5517db96d56Sopenharmony_ci        pos = cls._fields.index(key)
5527db96d56Sopenharmony_ci        if pos < len(args):
5537db96d56Sopenharmony_ci            raise TypeError(f"{cls.__name__} got multiple values for argument {key!r}")
5547db96d56Sopenharmony_ci    if cls in _const_types:
5557db96d56Sopenharmony_ci        return Constant(*args, **kwargs)
5567db96d56Sopenharmony_ci    return Constant.__new__(cls, *args, **kwargs)
5577db96d56Sopenharmony_ci
5587db96d56Sopenharmony_ciclass Num(Constant, metaclass=_ABC):
5597db96d56Sopenharmony_ci    _fields = ('n',)
5607db96d56Sopenharmony_ci    __new__ = _new
5617db96d56Sopenharmony_ci
5627db96d56Sopenharmony_ciclass Str(Constant, metaclass=_ABC):
5637db96d56Sopenharmony_ci    _fields = ('s',)
5647db96d56Sopenharmony_ci    __new__ = _new
5657db96d56Sopenharmony_ci
5667db96d56Sopenharmony_ciclass Bytes(Constant, metaclass=_ABC):
5677db96d56Sopenharmony_ci    _fields = ('s',)
5687db96d56Sopenharmony_ci    __new__ = _new
5697db96d56Sopenharmony_ci
5707db96d56Sopenharmony_ciclass NameConstant(Constant, metaclass=_ABC):
5717db96d56Sopenharmony_ci    __new__ = _new
5727db96d56Sopenharmony_ci
5737db96d56Sopenharmony_ciclass Ellipsis(Constant, metaclass=_ABC):
5747db96d56Sopenharmony_ci    _fields = ()
5757db96d56Sopenharmony_ci
5767db96d56Sopenharmony_ci    def __new__(cls, *args, **kwargs):
5777db96d56Sopenharmony_ci        if cls is Ellipsis:
5787db96d56Sopenharmony_ci            return Constant(..., *args, **kwargs)
5797db96d56Sopenharmony_ci        return Constant.__new__(cls, *args, **kwargs)
5807db96d56Sopenharmony_ci
5817db96d56Sopenharmony_ci_const_types = {
5827db96d56Sopenharmony_ci    Num: (int, float, complex),
5837db96d56Sopenharmony_ci    Str: (str,),
5847db96d56Sopenharmony_ci    Bytes: (bytes,),
5857db96d56Sopenharmony_ci    NameConstant: (type(None), bool),
5867db96d56Sopenharmony_ci    Ellipsis: (type(...),),
5877db96d56Sopenharmony_ci}
5887db96d56Sopenharmony_ci_const_types_not = {
5897db96d56Sopenharmony_ci    Num: (bool,),
5907db96d56Sopenharmony_ci}
5917db96d56Sopenharmony_ci
5927db96d56Sopenharmony_ci_const_node_type_names = {
5937db96d56Sopenharmony_ci    bool: 'NameConstant',  # should be before int
5947db96d56Sopenharmony_ci    type(None): 'NameConstant',
5957db96d56Sopenharmony_ci    int: 'Num',
5967db96d56Sopenharmony_ci    float: 'Num',
5977db96d56Sopenharmony_ci    complex: 'Num',
5987db96d56Sopenharmony_ci    str: 'Str',
5997db96d56Sopenharmony_ci    bytes: 'Bytes',
6007db96d56Sopenharmony_ci    type(...): 'Ellipsis',
6017db96d56Sopenharmony_ci}
6027db96d56Sopenharmony_ci
6037db96d56Sopenharmony_ciclass slice(AST):
6047db96d56Sopenharmony_ci    """Deprecated AST node class."""
6057db96d56Sopenharmony_ci
6067db96d56Sopenharmony_ciclass Index(slice):
6077db96d56Sopenharmony_ci    """Deprecated AST node class. Use the index value directly instead."""
6087db96d56Sopenharmony_ci    def __new__(cls, value, **kwargs):
6097db96d56Sopenharmony_ci        return value
6107db96d56Sopenharmony_ci
6117db96d56Sopenharmony_ciclass ExtSlice(slice):
6127db96d56Sopenharmony_ci    """Deprecated AST node class. Use ast.Tuple instead."""
6137db96d56Sopenharmony_ci    def __new__(cls, dims=(), **kwargs):
6147db96d56Sopenharmony_ci        return Tuple(list(dims), Load(), **kwargs)
6157db96d56Sopenharmony_ci
6167db96d56Sopenharmony_ci# If the ast module is loaded more than once, only add deprecated methods once
6177db96d56Sopenharmony_ciif not hasattr(Tuple, 'dims'):
6187db96d56Sopenharmony_ci    # The following code is for backward compatibility.
6197db96d56Sopenharmony_ci    # It will be removed in future.
6207db96d56Sopenharmony_ci
6217db96d56Sopenharmony_ci    def _dims_getter(self):
6227db96d56Sopenharmony_ci        """Deprecated. Use elts instead."""
6237db96d56Sopenharmony_ci        return self.elts
6247db96d56Sopenharmony_ci
6257db96d56Sopenharmony_ci    def _dims_setter(self, value):
6267db96d56Sopenharmony_ci        self.elts = value
6277db96d56Sopenharmony_ci
6287db96d56Sopenharmony_ci    Tuple.dims = property(_dims_getter, _dims_setter)
6297db96d56Sopenharmony_ci
6307db96d56Sopenharmony_ciclass Suite(mod):
6317db96d56Sopenharmony_ci    """Deprecated AST node class.  Unused in Python 3."""
6327db96d56Sopenharmony_ci
6337db96d56Sopenharmony_ciclass AugLoad(expr_context):
6347db96d56Sopenharmony_ci    """Deprecated AST node class.  Unused in Python 3."""
6357db96d56Sopenharmony_ci
6367db96d56Sopenharmony_ciclass AugStore(expr_context):
6377db96d56Sopenharmony_ci    """Deprecated AST node class.  Unused in Python 3."""
6387db96d56Sopenharmony_ci
6397db96d56Sopenharmony_ciclass Param(expr_context):
6407db96d56Sopenharmony_ci    """Deprecated AST node class.  Unused in Python 3."""
6417db96d56Sopenharmony_ci
6427db96d56Sopenharmony_ci
6437db96d56Sopenharmony_ci# Large float and imaginary literals get turned into infinities in the AST.
6447db96d56Sopenharmony_ci# We unparse those infinities to INFSTR.
6457db96d56Sopenharmony_ci_INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1)
6467db96d56Sopenharmony_ci
6477db96d56Sopenharmony_ci@_simple_enum(IntEnum)
6487db96d56Sopenharmony_ciclass _Precedence:
6497db96d56Sopenharmony_ci    """Precedence table that originated from python grammar."""
6507db96d56Sopenharmony_ci
6517db96d56Sopenharmony_ci    NAMED_EXPR = auto()      # <target> := <expr1>
6527db96d56Sopenharmony_ci    TUPLE = auto()           # <expr1>, <expr2>
6537db96d56Sopenharmony_ci    YIELD = auto()           # 'yield', 'yield from'
6547db96d56Sopenharmony_ci    TEST = auto()            # 'if'-'else', 'lambda'
6557db96d56Sopenharmony_ci    OR = auto()              # 'or'
6567db96d56Sopenharmony_ci    AND = auto()             # 'and'
6577db96d56Sopenharmony_ci    NOT = auto()             # 'not'
6587db96d56Sopenharmony_ci    CMP = auto()             # '<', '>', '==', '>=', '<=', '!=',
6597db96d56Sopenharmony_ci                             # 'in', 'not in', 'is', 'is not'
6607db96d56Sopenharmony_ci    EXPR = auto()
6617db96d56Sopenharmony_ci    BOR = EXPR               # '|'
6627db96d56Sopenharmony_ci    BXOR = auto()            # '^'
6637db96d56Sopenharmony_ci    BAND = auto()            # '&'
6647db96d56Sopenharmony_ci    SHIFT = auto()           # '<<', '>>'
6657db96d56Sopenharmony_ci    ARITH = auto()           # '+', '-'
6667db96d56Sopenharmony_ci    TERM = auto()            # '*', '@', '/', '%', '//'
6677db96d56Sopenharmony_ci    FACTOR = auto()          # unary '+', '-', '~'
6687db96d56Sopenharmony_ci    POWER = auto()           # '**'
6697db96d56Sopenharmony_ci    AWAIT = auto()           # 'await'
6707db96d56Sopenharmony_ci    ATOM = auto()
6717db96d56Sopenharmony_ci
6727db96d56Sopenharmony_ci    def next(self):
6737db96d56Sopenharmony_ci        try:
6747db96d56Sopenharmony_ci            return self.__class__(self + 1)
6757db96d56Sopenharmony_ci        except ValueError:
6767db96d56Sopenharmony_ci            return self
6777db96d56Sopenharmony_ci
6787db96d56Sopenharmony_ci
6797db96d56Sopenharmony_ci_SINGLE_QUOTES = ("'", '"')
6807db96d56Sopenharmony_ci_MULTI_QUOTES = ('"""', "'''")
6817db96d56Sopenharmony_ci_ALL_QUOTES = (*_SINGLE_QUOTES, *_MULTI_QUOTES)
6827db96d56Sopenharmony_ci
6837db96d56Sopenharmony_ciclass _Unparser(NodeVisitor):
6847db96d56Sopenharmony_ci    """Methods in this class recursively traverse an AST and
6857db96d56Sopenharmony_ci    output source code for the abstract syntax; original formatting
6867db96d56Sopenharmony_ci    is disregarded."""
6877db96d56Sopenharmony_ci
6887db96d56Sopenharmony_ci    def __init__(self, *, _avoid_backslashes=False):
6897db96d56Sopenharmony_ci        self._source = []
6907db96d56Sopenharmony_ci        self._precedences = {}
6917db96d56Sopenharmony_ci        self._type_ignores = {}
6927db96d56Sopenharmony_ci        self._indent = 0
6937db96d56Sopenharmony_ci        self._avoid_backslashes = _avoid_backslashes
6947db96d56Sopenharmony_ci        self._in_try_star = False
6957db96d56Sopenharmony_ci
6967db96d56Sopenharmony_ci    def interleave(self, inter, f, seq):
6977db96d56Sopenharmony_ci        """Call f on each item in seq, calling inter() in between."""
6987db96d56Sopenharmony_ci        seq = iter(seq)
6997db96d56Sopenharmony_ci        try:
7007db96d56Sopenharmony_ci            f(next(seq))
7017db96d56Sopenharmony_ci        except StopIteration:
7027db96d56Sopenharmony_ci            pass
7037db96d56Sopenharmony_ci        else:
7047db96d56Sopenharmony_ci            for x in seq:
7057db96d56Sopenharmony_ci                inter()
7067db96d56Sopenharmony_ci                f(x)
7077db96d56Sopenharmony_ci
7087db96d56Sopenharmony_ci    def items_view(self, traverser, items):
7097db96d56Sopenharmony_ci        """Traverse and separate the given *items* with a comma and append it to
7107db96d56Sopenharmony_ci        the buffer. If *items* is a single item sequence, a trailing comma
7117db96d56Sopenharmony_ci        will be added."""
7127db96d56Sopenharmony_ci        if len(items) == 1:
7137db96d56Sopenharmony_ci            traverser(items[0])
7147db96d56Sopenharmony_ci            self.write(",")
7157db96d56Sopenharmony_ci        else:
7167db96d56Sopenharmony_ci            self.interleave(lambda: self.write(", "), traverser, items)
7177db96d56Sopenharmony_ci
7187db96d56Sopenharmony_ci    def maybe_newline(self):
7197db96d56Sopenharmony_ci        """Adds a newline if it isn't the start of generated source"""
7207db96d56Sopenharmony_ci        if self._source:
7217db96d56Sopenharmony_ci            self.write("\n")
7227db96d56Sopenharmony_ci
7237db96d56Sopenharmony_ci    def fill(self, text=""):
7247db96d56Sopenharmony_ci        """Indent a piece of text and append it, according to the current
7257db96d56Sopenharmony_ci        indentation level"""
7267db96d56Sopenharmony_ci        self.maybe_newline()
7277db96d56Sopenharmony_ci        self.write("    " * self._indent + text)
7287db96d56Sopenharmony_ci
7297db96d56Sopenharmony_ci    def write(self, *text):
7307db96d56Sopenharmony_ci        """Add new source parts"""
7317db96d56Sopenharmony_ci        self._source.extend(text)
7327db96d56Sopenharmony_ci
7337db96d56Sopenharmony_ci    @contextmanager
7347db96d56Sopenharmony_ci    def buffered(self, buffer = None):
7357db96d56Sopenharmony_ci        if buffer is None:
7367db96d56Sopenharmony_ci            buffer = []
7377db96d56Sopenharmony_ci
7387db96d56Sopenharmony_ci        original_source = self._source
7397db96d56Sopenharmony_ci        self._source = buffer
7407db96d56Sopenharmony_ci        yield buffer
7417db96d56Sopenharmony_ci        self._source = original_source
7427db96d56Sopenharmony_ci
7437db96d56Sopenharmony_ci    @contextmanager
7447db96d56Sopenharmony_ci    def block(self, *, extra = None):
7457db96d56Sopenharmony_ci        """A context manager for preparing the source for blocks. It adds
7467db96d56Sopenharmony_ci        the character':', increases the indentation on enter and decreases
7477db96d56Sopenharmony_ci        the indentation on exit. If *extra* is given, it will be directly
7487db96d56Sopenharmony_ci        appended after the colon character.
7497db96d56Sopenharmony_ci        """
7507db96d56Sopenharmony_ci        self.write(":")
7517db96d56Sopenharmony_ci        if extra:
7527db96d56Sopenharmony_ci            self.write(extra)
7537db96d56Sopenharmony_ci        self._indent += 1
7547db96d56Sopenharmony_ci        yield
7557db96d56Sopenharmony_ci        self._indent -= 1
7567db96d56Sopenharmony_ci
7577db96d56Sopenharmony_ci    @contextmanager
7587db96d56Sopenharmony_ci    def delimit(self, start, end):
7597db96d56Sopenharmony_ci        """A context manager for preparing the source for expressions. It adds
7607db96d56Sopenharmony_ci        *start* to the buffer and enters, after exit it adds *end*."""
7617db96d56Sopenharmony_ci
7627db96d56Sopenharmony_ci        self.write(start)
7637db96d56Sopenharmony_ci        yield
7647db96d56Sopenharmony_ci        self.write(end)
7657db96d56Sopenharmony_ci
7667db96d56Sopenharmony_ci    def delimit_if(self, start, end, condition):
7677db96d56Sopenharmony_ci        if condition:
7687db96d56Sopenharmony_ci            return self.delimit(start, end)
7697db96d56Sopenharmony_ci        else:
7707db96d56Sopenharmony_ci            return nullcontext()
7717db96d56Sopenharmony_ci
7727db96d56Sopenharmony_ci    def require_parens(self, precedence, node):
7737db96d56Sopenharmony_ci        """Shortcut to adding precedence related parens"""
7747db96d56Sopenharmony_ci        return self.delimit_if("(", ")", self.get_precedence(node) > precedence)
7757db96d56Sopenharmony_ci
7767db96d56Sopenharmony_ci    def get_precedence(self, node):
7777db96d56Sopenharmony_ci        return self._precedences.get(node, _Precedence.TEST)
7787db96d56Sopenharmony_ci
7797db96d56Sopenharmony_ci    def set_precedence(self, precedence, *nodes):
7807db96d56Sopenharmony_ci        for node in nodes:
7817db96d56Sopenharmony_ci            self._precedences[node] = precedence
7827db96d56Sopenharmony_ci
7837db96d56Sopenharmony_ci    def get_raw_docstring(self, node):
7847db96d56Sopenharmony_ci        """If a docstring node is found in the body of the *node* parameter,
7857db96d56Sopenharmony_ci        return that docstring node, None otherwise.
7867db96d56Sopenharmony_ci
7877db96d56Sopenharmony_ci        Logic mirrored from ``_PyAST_GetDocString``."""
7887db96d56Sopenharmony_ci        if not isinstance(
7897db96d56Sopenharmony_ci            node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)
7907db96d56Sopenharmony_ci        ) or len(node.body) < 1:
7917db96d56Sopenharmony_ci            return None
7927db96d56Sopenharmony_ci        node = node.body[0]
7937db96d56Sopenharmony_ci        if not isinstance(node, Expr):
7947db96d56Sopenharmony_ci            return None
7957db96d56Sopenharmony_ci        node = node.value
7967db96d56Sopenharmony_ci        if isinstance(node, Constant) and isinstance(node.value, str):
7977db96d56Sopenharmony_ci            return node
7987db96d56Sopenharmony_ci
7997db96d56Sopenharmony_ci    def get_type_comment(self, node):
8007db96d56Sopenharmony_ci        comment = self._type_ignores.get(node.lineno) or node.type_comment
8017db96d56Sopenharmony_ci        if comment is not None:
8027db96d56Sopenharmony_ci            return f" # type: {comment}"
8037db96d56Sopenharmony_ci
8047db96d56Sopenharmony_ci    def traverse(self, node):
8057db96d56Sopenharmony_ci        if isinstance(node, list):
8067db96d56Sopenharmony_ci            for item in node:
8077db96d56Sopenharmony_ci                self.traverse(item)
8087db96d56Sopenharmony_ci        else:
8097db96d56Sopenharmony_ci            super().visit(node)
8107db96d56Sopenharmony_ci
8117db96d56Sopenharmony_ci    # Note: as visit() resets the output text, do NOT rely on
8127db96d56Sopenharmony_ci    # NodeVisitor.generic_visit to handle any nodes (as it calls back in to
8137db96d56Sopenharmony_ci    # the subclass visit() method, which resets self._source to an empty list)
8147db96d56Sopenharmony_ci    def visit(self, node):
8157db96d56Sopenharmony_ci        """Outputs a source code string that, if converted back to an ast
8167db96d56Sopenharmony_ci        (using ast.parse) will generate an AST equivalent to *node*"""
8177db96d56Sopenharmony_ci        self._source = []
8187db96d56Sopenharmony_ci        self.traverse(node)
8197db96d56Sopenharmony_ci        return "".join(self._source)
8207db96d56Sopenharmony_ci
8217db96d56Sopenharmony_ci    def _write_docstring_and_traverse_body(self, node):
8227db96d56Sopenharmony_ci        if (docstring := self.get_raw_docstring(node)):
8237db96d56Sopenharmony_ci            self._write_docstring(docstring)
8247db96d56Sopenharmony_ci            self.traverse(node.body[1:])
8257db96d56Sopenharmony_ci        else:
8267db96d56Sopenharmony_ci            self.traverse(node.body)
8277db96d56Sopenharmony_ci
8287db96d56Sopenharmony_ci    def visit_Module(self, node):
8297db96d56Sopenharmony_ci        self._type_ignores = {
8307db96d56Sopenharmony_ci            ignore.lineno: f"ignore{ignore.tag}"
8317db96d56Sopenharmony_ci            for ignore in node.type_ignores
8327db96d56Sopenharmony_ci        }
8337db96d56Sopenharmony_ci        self._write_docstring_and_traverse_body(node)
8347db96d56Sopenharmony_ci        self._type_ignores.clear()
8357db96d56Sopenharmony_ci
8367db96d56Sopenharmony_ci    def visit_FunctionType(self, node):
8377db96d56Sopenharmony_ci        with self.delimit("(", ")"):
8387db96d56Sopenharmony_ci            self.interleave(
8397db96d56Sopenharmony_ci                lambda: self.write(", "), self.traverse, node.argtypes
8407db96d56Sopenharmony_ci            )
8417db96d56Sopenharmony_ci
8427db96d56Sopenharmony_ci        self.write(" -> ")
8437db96d56Sopenharmony_ci        self.traverse(node.returns)
8447db96d56Sopenharmony_ci
8457db96d56Sopenharmony_ci    def visit_Expr(self, node):
8467db96d56Sopenharmony_ci        self.fill()
8477db96d56Sopenharmony_ci        self.set_precedence(_Precedence.YIELD, node.value)
8487db96d56Sopenharmony_ci        self.traverse(node.value)
8497db96d56Sopenharmony_ci
8507db96d56Sopenharmony_ci    def visit_NamedExpr(self, node):
8517db96d56Sopenharmony_ci        with self.require_parens(_Precedence.NAMED_EXPR, node):
8527db96d56Sopenharmony_ci            self.set_precedence(_Precedence.ATOM, node.target, node.value)
8537db96d56Sopenharmony_ci            self.traverse(node.target)
8547db96d56Sopenharmony_ci            self.write(" := ")
8557db96d56Sopenharmony_ci            self.traverse(node.value)
8567db96d56Sopenharmony_ci
8577db96d56Sopenharmony_ci    def visit_Import(self, node):
8587db96d56Sopenharmony_ci        self.fill("import ")
8597db96d56Sopenharmony_ci        self.interleave(lambda: self.write(", "), self.traverse, node.names)
8607db96d56Sopenharmony_ci
8617db96d56Sopenharmony_ci    def visit_ImportFrom(self, node):
8627db96d56Sopenharmony_ci        self.fill("from ")
8637db96d56Sopenharmony_ci        self.write("." * (node.level or 0))
8647db96d56Sopenharmony_ci        if node.module:
8657db96d56Sopenharmony_ci            self.write(node.module)
8667db96d56Sopenharmony_ci        self.write(" import ")
8677db96d56Sopenharmony_ci        self.interleave(lambda: self.write(", "), self.traverse, node.names)
8687db96d56Sopenharmony_ci
8697db96d56Sopenharmony_ci    def visit_Assign(self, node):
8707db96d56Sopenharmony_ci        self.fill()
8717db96d56Sopenharmony_ci        for target in node.targets:
8727db96d56Sopenharmony_ci            self.set_precedence(_Precedence.TUPLE, target)
8737db96d56Sopenharmony_ci            self.traverse(target)
8747db96d56Sopenharmony_ci            self.write(" = ")
8757db96d56Sopenharmony_ci        self.traverse(node.value)
8767db96d56Sopenharmony_ci        if type_comment := self.get_type_comment(node):
8777db96d56Sopenharmony_ci            self.write(type_comment)
8787db96d56Sopenharmony_ci
8797db96d56Sopenharmony_ci    def visit_AugAssign(self, node):
8807db96d56Sopenharmony_ci        self.fill()
8817db96d56Sopenharmony_ci        self.traverse(node.target)
8827db96d56Sopenharmony_ci        self.write(" " + self.binop[node.op.__class__.__name__] + "= ")
8837db96d56Sopenharmony_ci        self.traverse(node.value)
8847db96d56Sopenharmony_ci
8857db96d56Sopenharmony_ci    def visit_AnnAssign(self, node):
8867db96d56Sopenharmony_ci        self.fill()
8877db96d56Sopenharmony_ci        with self.delimit_if("(", ")", not node.simple and isinstance(node.target, Name)):
8887db96d56Sopenharmony_ci            self.traverse(node.target)
8897db96d56Sopenharmony_ci        self.write(": ")
8907db96d56Sopenharmony_ci        self.traverse(node.annotation)
8917db96d56Sopenharmony_ci        if node.value:
8927db96d56Sopenharmony_ci            self.write(" = ")
8937db96d56Sopenharmony_ci            self.traverse(node.value)
8947db96d56Sopenharmony_ci
8957db96d56Sopenharmony_ci    def visit_Return(self, node):
8967db96d56Sopenharmony_ci        self.fill("return")
8977db96d56Sopenharmony_ci        if node.value:
8987db96d56Sopenharmony_ci            self.write(" ")
8997db96d56Sopenharmony_ci            self.traverse(node.value)
9007db96d56Sopenharmony_ci
9017db96d56Sopenharmony_ci    def visit_Pass(self, node):
9027db96d56Sopenharmony_ci        self.fill("pass")
9037db96d56Sopenharmony_ci
9047db96d56Sopenharmony_ci    def visit_Break(self, node):
9057db96d56Sopenharmony_ci        self.fill("break")
9067db96d56Sopenharmony_ci
9077db96d56Sopenharmony_ci    def visit_Continue(self, node):
9087db96d56Sopenharmony_ci        self.fill("continue")
9097db96d56Sopenharmony_ci
9107db96d56Sopenharmony_ci    def visit_Delete(self, node):
9117db96d56Sopenharmony_ci        self.fill("del ")
9127db96d56Sopenharmony_ci        self.interleave(lambda: self.write(", "), self.traverse, node.targets)
9137db96d56Sopenharmony_ci
9147db96d56Sopenharmony_ci    def visit_Assert(self, node):
9157db96d56Sopenharmony_ci        self.fill("assert ")
9167db96d56Sopenharmony_ci        self.traverse(node.test)
9177db96d56Sopenharmony_ci        if node.msg:
9187db96d56Sopenharmony_ci            self.write(", ")
9197db96d56Sopenharmony_ci            self.traverse(node.msg)
9207db96d56Sopenharmony_ci
9217db96d56Sopenharmony_ci    def visit_Global(self, node):
9227db96d56Sopenharmony_ci        self.fill("global ")
9237db96d56Sopenharmony_ci        self.interleave(lambda: self.write(", "), self.write, node.names)
9247db96d56Sopenharmony_ci
9257db96d56Sopenharmony_ci    def visit_Nonlocal(self, node):
9267db96d56Sopenharmony_ci        self.fill("nonlocal ")
9277db96d56Sopenharmony_ci        self.interleave(lambda: self.write(", "), self.write, node.names)
9287db96d56Sopenharmony_ci
9297db96d56Sopenharmony_ci    def visit_Await(self, node):
9307db96d56Sopenharmony_ci        with self.require_parens(_Precedence.AWAIT, node):
9317db96d56Sopenharmony_ci            self.write("await")
9327db96d56Sopenharmony_ci            if node.value:
9337db96d56Sopenharmony_ci                self.write(" ")
9347db96d56Sopenharmony_ci                self.set_precedence(_Precedence.ATOM, node.value)
9357db96d56Sopenharmony_ci                self.traverse(node.value)
9367db96d56Sopenharmony_ci
9377db96d56Sopenharmony_ci    def visit_Yield(self, node):
9387db96d56Sopenharmony_ci        with self.require_parens(_Precedence.YIELD, node):
9397db96d56Sopenharmony_ci            self.write("yield")
9407db96d56Sopenharmony_ci            if node.value:
9417db96d56Sopenharmony_ci                self.write(" ")
9427db96d56Sopenharmony_ci                self.set_precedence(_Precedence.ATOM, node.value)
9437db96d56Sopenharmony_ci                self.traverse(node.value)
9447db96d56Sopenharmony_ci
9457db96d56Sopenharmony_ci    def visit_YieldFrom(self, node):
9467db96d56Sopenharmony_ci        with self.require_parens(_Precedence.YIELD, node):
9477db96d56Sopenharmony_ci            self.write("yield from ")
9487db96d56Sopenharmony_ci            if not node.value:
9497db96d56Sopenharmony_ci                raise ValueError("Node can't be used without a value attribute.")
9507db96d56Sopenharmony_ci            self.set_precedence(_Precedence.ATOM, node.value)
9517db96d56Sopenharmony_ci            self.traverse(node.value)
9527db96d56Sopenharmony_ci
9537db96d56Sopenharmony_ci    def visit_Raise(self, node):
9547db96d56Sopenharmony_ci        self.fill("raise")
9557db96d56Sopenharmony_ci        if not node.exc:
9567db96d56Sopenharmony_ci            if node.cause:
9577db96d56Sopenharmony_ci                raise ValueError(f"Node can't use cause without an exception.")
9587db96d56Sopenharmony_ci            return
9597db96d56Sopenharmony_ci        self.write(" ")
9607db96d56Sopenharmony_ci        self.traverse(node.exc)
9617db96d56Sopenharmony_ci        if node.cause:
9627db96d56Sopenharmony_ci            self.write(" from ")
9637db96d56Sopenharmony_ci            self.traverse(node.cause)
9647db96d56Sopenharmony_ci
9657db96d56Sopenharmony_ci    def do_visit_try(self, node):
9667db96d56Sopenharmony_ci        self.fill("try")
9677db96d56Sopenharmony_ci        with self.block():
9687db96d56Sopenharmony_ci            self.traverse(node.body)
9697db96d56Sopenharmony_ci        for ex in node.handlers:
9707db96d56Sopenharmony_ci            self.traverse(ex)
9717db96d56Sopenharmony_ci        if node.orelse:
9727db96d56Sopenharmony_ci            self.fill("else")
9737db96d56Sopenharmony_ci            with self.block():
9747db96d56Sopenharmony_ci                self.traverse(node.orelse)
9757db96d56Sopenharmony_ci        if node.finalbody:
9767db96d56Sopenharmony_ci            self.fill("finally")
9777db96d56Sopenharmony_ci            with self.block():
9787db96d56Sopenharmony_ci                self.traverse(node.finalbody)
9797db96d56Sopenharmony_ci
9807db96d56Sopenharmony_ci    def visit_Try(self, node):
9817db96d56Sopenharmony_ci        prev_in_try_star = self._in_try_star
9827db96d56Sopenharmony_ci        try:
9837db96d56Sopenharmony_ci            self._in_try_star = False
9847db96d56Sopenharmony_ci            self.do_visit_try(node)
9857db96d56Sopenharmony_ci        finally:
9867db96d56Sopenharmony_ci            self._in_try_star = prev_in_try_star
9877db96d56Sopenharmony_ci
9887db96d56Sopenharmony_ci    def visit_TryStar(self, node):
9897db96d56Sopenharmony_ci        prev_in_try_star = self._in_try_star
9907db96d56Sopenharmony_ci        try:
9917db96d56Sopenharmony_ci            self._in_try_star = True
9927db96d56Sopenharmony_ci            self.do_visit_try(node)
9937db96d56Sopenharmony_ci        finally:
9947db96d56Sopenharmony_ci            self._in_try_star = prev_in_try_star
9957db96d56Sopenharmony_ci
9967db96d56Sopenharmony_ci    def visit_ExceptHandler(self, node):
9977db96d56Sopenharmony_ci        self.fill("except*" if self._in_try_star else "except")
9987db96d56Sopenharmony_ci        if node.type:
9997db96d56Sopenharmony_ci            self.write(" ")
10007db96d56Sopenharmony_ci            self.traverse(node.type)
10017db96d56Sopenharmony_ci        if node.name:
10027db96d56Sopenharmony_ci            self.write(" as ")
10037db96d56Sopenharmony_ci            self.write(node.name)
10047db96d56Sopenharmony_ci        with self.block():
10057db96d56Sopenharmony_ci            self.traverse(node.body)
10067db96d56Sopenharmony_ci
10077db96d56Sopenharmony_ci    def visit_ClassDef(self, node):
10087db96d56Sopenharmony_ci        self.maybe_newline()
10097db96d56Sopenharmony_ci        for deco in node.decorator_list:
10107db96d56Sopenharmony_ci            self.fill("@")
10117db96d56Sopenharmony_ci            self.traverse(deco)
10127db96d56Sopenharmony_ci        self.fill("class " + node.name)
10137db96d56Sopenharmony_ci        with self.delimit_if("(", ")", condition = node.bases or node.keywords):
10147db96d56Sopenharmony_ci            comma = False
10157db96d56Sopenharmony_ci            for e in node.bases:
10167db96d56Sopenharmony_ci                if comma:
10177db96d56Sopenharmony_ci                    self.write(", ")
10187db96d56Sopenharmony_ci                else:
10197db96d56Sopenharmony_ci                    comma = True
10207db96d56Sopenharmony_ci                self.traverse(e)
10217db96d56Sopenharmony_ci            for e in node.keywords:
10227db96d56Sopenharmony_ci                if comma:
10237db96d56Sopenharmony_ci                    self.write(", ")
10247db96d56Sopenharmony_ci                else:
10257db96d56Sopenharmony_ci                    comma = True
10267db96d56Sopenharmony_ci                self.traverse(e)
10277db96d56Sopenharmony_ci
10287db96d56Sopenharmony_ci        with self.block():
10297db96d56Sopenharmony_ci            self._write_docstring_and_traverse_body(node)
10307db96d56Sopenharmony_ci
10317db96d56Sopenharmony_ci    def visit_FunctionDef(self, node):
10327db96d56Sopenharmony_ci        self._function_helper(node, "def")
10337db96d56Sopenharmony_ci
10347db96d56Sopenharmony_ci    def visit_AsyncFunctionDef(self, node):
10357db96d56Sopenharmony_ci        self._function_helper(node, "async def")
10367db96d56Sopenharmony_ci
10377db96d56Sopenharmony_ci    def _function_helper(self, node, fill_suffix):
10387db96d56Sopenharmony_ci        self.maybe_newline()
10397db96d56Sopenharmony_ci        for deco in node.decorator_list:
10407db96d56Sopenharmony_ci            self.fill("@")
10417db96d56Sopenharmony_ci            self.traverse(deco)
10427db96d56Sopenharmony_ci        def_str = fill_suffix + " " + node.name
10437db96d56Sopenharmony_ci        self.fill(def_str)
10447db96d56Sopenharmony_ci        with self.delimit("(", ")"):
10457db96d56Sopenharmony_ci            self.traverse(node.args)
10467db96d56Sopenharmony_ci        if node.returns:
10477db96d56Sopenharmony_ci            self.write(" -> ")
10487db96d56Sopenharmony_ci            self.traverse(node.returns)
10497db96d56Sopenharmony_ci        with self.block(extra=self.get_type_comment(node)):
10507db96d56Sopenharmony_ci            self._write_docstring_and_traverse_body(node)
10517db96d56Sopenharmony_ci
10527db96d56Sopenharmony_ci    def visit_For(self, node):
10537db96d56Sopenharmony_ci        self._for_helper("for ", node)
10547db96d56Sopenharmony_ci
10557db96d56Sopenharmony_ci    def visit_AsyncFor(self, node):
10567db96d56Sopenharmony_ci        self._for_helper("async for ", node)
10577db96d56Sopenharmony_ci
10587db96d56Sopenharmony_ci    def _for_helper(self, fill, node):
10597db96d56Sopenharmony_ci        self.fill(fill)
10607db96d56Sopenharmony_ci        self.set_precedence(_Precedence.TUPLE, node.target)
10617db96d56Sopenharmony_ci        self.traverse(node.target)
10627db96d56Sopenharmony_ci        self.write(" in ")
10637db96d56Sopenharmony_ci        self.traverse(node.iter)
10647db96d56Sopenharmony_ci        with self.block(extra=self.get_type_comment(node)):
10657db96d56Sopenharmony_ci            self.traverse(node.body)
10667db96d56Sopenharmony_ci        if node.orelse:
10677db96d56Sopenharmony_ci            self.fill("else")
10687db96d56Sopenharmony_ci            with self.block():
10697db96d56Sopenharmony_ci                self.traverse(node.orelse)
10707db96d56Sopenharmony_ci
10717db96d56Sopenharmony_ci    def visit_If(self, node):
10727db96d56Sopenharmony_ci        self.fill("if ")
10737db96d56Sopenharmony_ci        self.traverse(node.test)
10747db96d56Sopenharmony_ci        with self.block():
10757db96d56Sopenharmony_ci            self.traverse(node.body)
10767db96d56Sopenharmony_ci        # collapse nested ifs into equivalent elifs.
10777db96d56Sopenharmony_ci        while node.orelse and len(node.orelse) == 1 and isinstance(node.orelse[0], If):
10787db96d56Sopenharmony_ci            node = node.orelse[0]
10797db96d56Sopenharmony_ci            self.fill("elif ")
10807db96d56Sopenharmony_ci            self.traverse(node.test)
10817db96d56Sopenharmony_ci            with self.block():
10827db96d56Sopenharmony_ci                self.traverse(node.body)
10837db96d56Sopenharmony_ci        # final else
10847db96d56Sopenharmony_ci        if node.orelse:
10857db96d56Sopenharmony_ci            self.fill("else")
10867db96d56Sopenharmony_ci            with self.block():
10877db96d56Sopenharmony_ci                self.traverse(node.orelse)
10887db96d56Sopenharmony_ci
10897db96d56Sopenharmony_ci    def visit_While(self, node):
10907db96d56Sopenharmony_ci        self.fill("while ")
10917db96d56Sopenharmony_ci        self.traverse(node.test)
10927db96d56Sopenharmony_ci        with self.block():
10937db96d56Sopenharmony_ci            self.traverse(node.body)
10947db96d56Sopenharmony_ci        if node.orelse:
10957db96d56Sopenharmony_ci            self.fill("else")
10967db96d56Sopenharmony_ci            with self.block():
10977db96d56Sopenharmony_ci                self.traverse(node.orelse)
10987db96d56Sopenharmony_ci
10997db96d56Sopenharmony_ci    def visit_With(self, node):
11007db96d56Sopenharmony_ci        self.fill("with ")
11017db96d56Sopenharmony_ci        self.interleave(lambda: self.write(", "), self.traverse, node.items)
11027db96d56Sopenharmony_ci        with self.block(extra=self.get_type_comment(node)):
11037db96d56Sopenharmony_ci            self.traverse(node.body)
11047db96d56Sopenharmony_ci
11057db96d56Sopenharmony_ci    def visit_AsyncWith(self, node):
11067db96d56Sopenharmony_ci        self.fill("async with ")
11077db96d56Sopenharmony_ci        self.interleave(lambda: self.write(", "), self.traverse, node.items)
11087db96d56Sopenharmony_ci        with self.block(extra=self.get_type_comment(node)):
11097db96d56Sopenharmony_ci            self.traverse(node.body)
11107db96d56Sopenharmony_ci
11117db96d56Sopenharmony_ci    def _str_literal_helper(
11127db96d56Sopenharmony_ci        self, string, *, quote_types=_ALL_QUOTES, escape_special_whitespace=False
11137db96d56Sopenharmony_ci    ):
11147db96d56Sopenharmony_ci        """Helper for writing string literals, minimizing escapes.
11157db96d56Sopenharmony_ci        Returns the tuple (string literal to write, possible quote types).
11167db96d56Sopenharmony_ci        """
11177db96d56Sopenharmony_ci        def escape_char(c):
11187db96d56Sopenharmony_ci            # \n and \t are non-printable, but we only escape them if
11197db96d56Sopenharmony_ci            # escape_special_whitespace is True
11207db96d56Sopenharmony_ci            if not escape_special_whitespace and c in "\n\t":
11217db96d56Sopenharmony_ci                return c
11227db96d56Sopenharmony_ci            # Always escape backslashes and other non-printable characters
11237db96d56Sopenharmony_ci            if c == "\\" or not c.isprintable():
11247db96d56Sopenharmony_ci                return c.encode("unicode_escape").decode("ascii")
11257db96d56Sopenharmony_ci            return c
11267db96d56Sopenharmony_ci
11277db96d56Sopenharmony_ci        escaped_string = "".join(map(escape_char, string))
11287db96d56Sopenharmony_ci        possible_quotes = quote_types
11297db96d56Sopenharmony_ci        if "\n" in escaped_string:
11307db96d56Sopenharmony_ci            possible_quotes = [q for q in possible_quotes if q in _MULTI_QUOTES]
11317db96d56Sopenharmony_ci        possible_quotes = [q for q in possible_quotes if q not in escaped_string]
11327db96d56Sopenharmony_ci        if not possible_quotes:
11337db96d56Sopenharmony_ci            # If there aren't any possible_quotes, fallback to using repr
11347db96d56Sopenharmony_ci            # on the original string. Try to use a quote from quote_types,
11357db96d56Sopenharmony_ci            # e.g., so that we use triple quotes for docstrings.
11367db96d56Sopenharmony_ci            string = repr(string)
11377db96d56Sopenharmony_ci            quote = next((q for q in quote_types if string[0] in q), string[0])
11387db96d56Sopenharmony_ci            return string[1:-1], [quote]
11397db96d56Sopenharmony_ci        if escaped_string:
11407db96d56Sopenharmony_ci            # Sort so that we prefer '''"''' over """\""""
11417db96d56Sopenharmony_ci            possible_quotes.sort(key=lambda q: q[0] == escaped_string[-1])
11427db96d56Sopenharmony_ci            # If we're using triple quotes and we'd need to escape a final
11437db96d56Sopenharmony_ci            # quote, escape it
11447db96d56Sopenharmony_ci            if possible_quotes[0][0] == escaped_string[-1]:
11457db96d56Sopenharmony_ci                assert len(possible_quotes[0]) == 3
11467db96d56Sopenharmony_ci                escaped_string = escaped_string[:-1] + "\\" + escaped_string[-1]
11477db96d56Sopenharmony_ci        return escaped_string, possible_quotes
11487db96d56Sopenharmony_ci
11497db96d56Sopenharmony_ci    def _write_str_avoiding_backslashes(self, string, *, quote_types=_ALL_QUOTES):
11507db96d56Sopenharmony_ci        """Write string literal value with a best effort attempt to avoid backslashes."""
11517db96d56Sopenharmony_ci        string, quote_types = self._str_literal_helper(string, quote_types=quote_types)
11527db96d56Sopenharmony_ci        quote_type = quote_types[0]
11537db96d56Sopenharmony_ci        self.write(f"{quote_type}{string}{quote_type}")
11547db96d56Sopenharmony_ci
11557db96d56Sopenharmony_ci    def visit_JoinedStr(self, node):
11567db96d56Sopenharmony_ci        self.write("f")
11577db96d56Sopenharmony_ci        if self._avoid_backslashes:
11587db96d56Sopenharmony_ci            with self.buffered() as buffer:
11597db96d56Sopenharmony_ci                self._write_fstring_inner(node)
11607db96d56Sopenharmony_ci            return self._write_str_avoiding_backslashes("".join(buffer))
11617db96d56Sopenharmony_ci
11627db96d56Sopenharmony_ci        # If we don't need to avoid backslashes globally (i.e., we only need
11637db96d56Sopenharmony_ci        # to avoid them inside FormattedValues), it's cosmetically preferred
11647db96d56Sopenharmony_ci        # to use escaped whitespace. That is, it's preferred to use backslashes
11657db96d56Sopenharmony_ci        # for cases like: f"{x}\n". To accomplish this, we keep track of what
11667db96d56Sopenharmony_ci        # in our buffer corresponds to FormattedValues and what corresponds to
11677db96d56Sopenharmony_ci        # Constant parts of the f-string, and allow escapes accordingly.
11687db96d56Sopenharmony_ci        fstring_parts = []
11697db96d56Sopenharmony_ci        for value in node.values:
11707db96d56Sopenharmony_ci            with self.buffered() as buffer:
11717db96d56Sopenharmony_ci                self._write_fstring_inner(value)
11727db96d56Sopenharmony_ci            fstring_parts.append(
11737db96d56Sopenharmony_ci                ("".join(buffer), isinstance(value, Constant))
11747db96d56Sopenharmony_ci            )
11757db96d56Sopenharmony_ci
11767db96d56Sopenharmony_ci        new_fstring_parts = []
11777db96d56Sopenharmony_ci        quote_types = list(_ALL_QUOTES)
11787db96d56Sopenharmony_ci        for value, is_constant in fstring_parts:
11797db96d56Sopenharmony_ci            value, quote_types = self._str_literal_helper(
11807db96d56Sopenharmony_ci                value,
11817db96d56Sopenharmony_ci                quote_types=quote_types,
11827db96d56Sopenharmony_ci                escape_special_whitespace=is_constant,
11837db96d56Sopenharmony_ci            )
11847db96d56Sopenharmony_ci            new_fstring_parts.append(value)
11857db96d56Sopenharmony_ci
11867db96d56Sopenharmony_ci        value = "".join(new_fstring_parts)
11877db96d56Sopenharmony_ci        quote_type = quote_types[0]
11887db96d56Sopenharmony_ci        self.write(f"{quote_type}{value}{quote_type}")
11897db96d56Sopenharmony_ci
11907db96d56Sopenharmony_ci    def _write_fstring_inner(self, node):
11917db96d56Sopenharmony_ci        if isinstance(node, JoinedStr):
11927db96d56Sopenharmony_ci            # for both the f-string itself, and format_spec
11937db96d56Sopenharmony_ci            for value in node.values:
11947db96d56Sopenharmony_ci                self._write_fstring_inner(value)
11957db96d56Sopenharmony_ci        elif isinstance(node, Constant) and isinstance(node.value, str):
11967db96d56Sopenharmony_ci            value = node.value.replace("{", "{{").replace("}", "}}")
11977db96d56Sopenharmony_ci            self.write(value)
11987db96d56Sopenharmony_ci        elif isinstance(node, FormattedValue):
11997db96d56Sopenharmony_ci            self.visit_FormattedValue(node)
12007db96d56Sopenharmony_ci        else:
12017db96d56Sopenharmony_ci            raise ValueError(f"Unexpected node inside JoinedStr, {node!r}")
12027db96d56Sopenharmony_ci
12037db96d56Sopenharmony_ci    def visit_FormattedValue(self, node):
12047db96d56Sopenharmony_ci        def unparse_inner(inner):
12057db96d56Sopenharmony_ci            unparser = type(self)(_avoid_backslashes=True)
12067db96d56Sopenharmony_ci            unparser.set_precedence(_Precedence.TEST.next(), inner)
12077db96d56Sopenharmony_ci            return unparser.visit(inner)
12087db96d56Sopenharmony_ci
12097db96d56Sopenharmony_ci        with self.delimit("{", "}"):
12107db96d56Sopenharmony_ci            expr = unparse_inner(node.value)
12117db96d56Sopenharmony_ci            if "\\" in expr:
12127db96d56Sopenharmony_ci                raise ValueError(
12137db96d56Sopenharmony_ci                    "Unable to avoid backslash in f-string expression part"
12147db96d56Sopenharmony_ci                )
12157db96d56Sopenharmony_ci            if expr.startswith("{"):
12167db96d56Sopenharmony_ci                # Separate pair of opening brackets as "{ {"
12177db96d56Sopenharmony_ci                self.write(" ")
12187db96d56Sopenharmony_ci            self.write(expr)
12197db96d56Sopenharmony_ci            if node.conversion != -1:
12207db96d56Sopenharmony_ci                self.write(f"!{chr(node.conversion)}")
12217db96d56Sopenharmony_ci            if node.format_spec:
12227db96d56Sopenharmony_ci                self.write(":")
12237db96d56Sopenharmony_ci                self._write_fstring_inner(node.format_spec)
12247db96d56Sopenharmony_ci
12257db96d56Sopenharmony_ci    def visit_Name(self, node):
12267db96d56Sopenharmony_ci        self.write(node.id)
12277db96d56Sopenharmony_ci
12287db96d56Sopenharmony_ci    def _write_docstring(self, node):
12297db96d56Sopenharmony_ci        self.fill()
12307db96d56Sopenharmony_ci        if node.kind == "u":
12317db96d56Sopenharmony_ci            self.write("u")
12327db96d56Sopenharmony_ci        self._write_str_avoiding_backslashes(node.value, quote_types=_MULTI_QUOTES)
12337db96d56Sopenharmony_ci
12347db96d56Sopenharmony_ci    def _write_constant(self, value):
12357db96d56Sopenharmony_ci        if isinstance(value, (float, complex)):
12367db96d56Sopenharmony_ci            # Substitute overflowing decimal literal for AST infinities,
12377db96d56Sopenharmony_ci            # and inf - inf for NaNs.
12387db96d56Sopenharmony_ci            self.write(
12397db96d56Sopenharmony_ci                repr(value)
12407db96d56Sopenharmony_ci                .replace("inf", _INFSTR)
12417db96d56Sopenharmony_ci                .replace("nan", f"({_INFSTR}-{_INFSTR})")
12427db96d56Sopenharmony_ci            )
12437db96d56Sopenharmony_ci        elif self._avoid_backslashes and isinstance(value, str):
12447db96d56Sopenharmony_ci            self._write_str_avoiding_backslashes(value)
12457db96d56Sopenharmony_ci        else:
12467db96d56Sopenharmony_ci            self.write(repr(value))
12477db96d56Sopenharmony_ci
12487db96d56Sopenharmony_ci    def visit_Constant(self, node):
12497db96d56Sopenharmony_ci        value = node.value
12507db96d56Sopenharmony_ci        if isinstance(value, tuple):
12517db96d56Sopenharmony_ci            with self.delimit("(", ")"):
12527db96d56Sopenharmony_ci                self.items_view(self._write_constant, value)
12537db96d56Sopenharmony_ci        elif value is ...:
12547db96d56Sopenharmony_ci            self.write("...")
12557db96d56Sopenharmony_ci        else:
12567db96d56Sopenharmony_ci            if node.kind == "u":
12577db96d56Sopenharmony_ci                self.write("u")
12587db96d56Sopenharmony_ci            self._write_constant(node.value)
12597db96d56Sopenharmony_ci
12607db96d56Sopenharmony_ci    def visit_List(self, node):
12617db96d56Sopenharmony_ci        with self.delimit("[", "]"):
12627db96d56Sopenharmony_ci            self.interleave(lambda: self.write(", "), self.traverse, node.elts)
12637db96d56Sopenharmony_ci
12647db96d56Sopenharmony_ci    def visit_ListComp(self, node):
12657db96d56Sopenharmony_ci        with self.delimit("[", "]"):
12667db96d56Sopenharmony_ci            self.traverse(node.elt)
12677db96d56Sopenharmony_ci            for gen in node.generators:
12687db96d56Sopenharmony_ci                self.traverse(gen)
12697db96d56Sopenharmony_ci
12707db96d56Sopenharmony_ci    def visit_GeneratorExp(self, node):
12717db96d56Sopenharmony_ci        with self.delimit("(", ")"):
12727db96d56Sopenharmony_ci            self.traverse(node.elt)
12737db96d56Sopenharmony_ci            for gen in node.generators:
12747db96d56Sopenharmony_ci                self.traverse(gen)
12757db96d56Sopenharmony_ci
12767db96d56Sopenharmony_ci    def visit_SetComp(self, node):
12777db96d56Sopenharmony_ci        with self.delimit("{", "}"):
12787db96d56Sopenharmony_ci            self.traverse(node.elt)
12797db96d56Sopenharmony_ci            for gen in node.generators:
12807db96d56Sopenharmony_ci                self.traverse(gen)
12817db96d56Sopenharmony_ci
12827db96d56Sopenharmony_ci    def visit_DictComp(self, node):
12837db96d56Sopenharmony_ci        with self.delimit("{", "}"):
12847db96d56Sopenharmony_ci            self.traverse(node.key)
12857db96d56Sopenharmony_ci            self.write(": ")
12867db96d56Sopenharmony_ci            self.traverse(node.value)
12877db96d56Sopenharmony_ci            for gen in node.generators:
12887db96d56Sopenharmony_ci                self.traverse(gen)
12897db96d56Sopenharmony_ci
12907db96d56Sopenharmony_ci    def visit_comprehension(self, node):
12917db96d56Sopenharmony_ci        if node.is_async:
12927db96d56Sopenharmony_ci            self.write(" async for ")
12937db96d56Sopenharmony_ci        else:
12947db96d56Sopenharmony_ci            self.write(" for ")
12957db96d56Sopenharmony_ci        self.set_precedence(_Precedence.TUPLE, node.target)
12967db96d56Sopenharmony_ci        self.traverse(node.target)
12977db96d56Sopenharmony_ci        self.write(" in ")
12987db96d56Sopenharmony_ci        self.set_precedence(_Precedence.TEST.next(), node.iter, *node.ifs)
12997db96d56Sopenharmony_ci        self.traverse(node.iter)
13007db96d56Sopenharmony_ci        for if_clause in node.ifs:
13017db96d56Sopenharmony_ci            self.write(" if ")
13027db96d56Sopenharmony_ci            self.traverse(if_clause)
13037db96d56Sopenharmony_ci
13047db96d56Sopenharmony_ci    def visit_IfExp(self, node):
13057db96d56Sopenharmony_ci        with self.require_parens(_Precedence.TEST, node):
13067db96d56Sopenharmony_ci            self.set_precedence(_Precedence.TEST.next(), node.body, node.test)
13077db96d56Sopenharmony_ci            self.traverse(node.body)
13087db96d56Sopenharmony_ci            self.write(" if ")
13097db96d56Sopenharmony_ci            self.traverse(node.test)
13107db96d56Sopenharmony_ci            self.write(" else ")
13117db96d56Sopenharmony_ci            self.set_precedence(_Precedence.TEST, node.orelse)
13127db96d56Sopenharmony_ci            self.traverse(node.orelse)
13137db96d56Sopenharmony_ci
13147db96d56Sopenharmony_ci    def visit_Set(self, node):
13157db96d56Sopenharmony_ci        if node.elts:
13167db96d56Sopenharmony_ci            with self.delimit("{", "}"):
13177db96d56Sopenharmony_ci                self.interleave(lambda: self.write(", "), self.traverse, node.elts)
13187db96d56Sopenharmony_ci        else:
13197db96d56Sopenharmony_ci            # `{}` would be interpreted as a dictionary literal, and
13207db96d56Sopenharmony_ci            # `set` might be shadowed. Thus:
13217db96d56Sopenharmony_ci            self.write('{*()}')
13227db96d56Sopenharmony_ci
13237db96d56Sopenharmony_ci    def visit_Dict(self, node):
13247db96d56Sopenharmony_ci        def write_key_value_pair(k, v):
13257db96d56Sopenharmony_ci            self.traverse(k)
13267db96d56Sopenharmony_ci            self.write(": ")
13277db96d56Sopenharmony_ci            self.traverse(v)
13287db96d56Sopenharmony_ci
13297db96d56Sopenharmony_ci        def write_item(item):
13307db96d56Sopenharmony_ci            k, v = item
13317db96d56Sopenharmony_ci            if k is None:
13327db96d56Sopenharmony_ci                # for dictionary unpacking operator in dicts {**{'y': 2}}
13337db96d56Sopenharmony_ci                # see PEP 448 for details
13347db96d56Sopenharmony_ci                self.write("**")
13357db96d56Sopenharmony_ci                self.set_precedence(_Precedence.EXPR, v)
13367db96d56Sopenharmony_ci                self.traverse(v)
13377db96d56Sopenharmony_ci            else:
13387db96d56Sopenharmony_ci                write_key_value_pair(k, v)
13397db96d56Sopenharmony_ci
13407db96d56Sopenharmony_ci        with self.delimit("{", "}"):
13417db96d56Sopenharmony_ci            self.interleave(
13427db96d56Sopenharmony_ci                lambda: self.write(", "), write_item, zip(node.keys, node.values)
13437db96d56Sopenharmony_ci            )
13447db96d56Sopenharmony_ci
13457db96d56Sopenharmony_ci    def visit_Tuple(self, node):
13467db96d56Sopenharmony_ci        with self.delimit_if(
13477db96d56Sopenharmony_ci            "(",
13487db96d56Sopenharmony_ci            ")",
13497db96d56Sopenharmony_ci            len(node.elts) == 0 or self.get_precedence(node) > _Precedence.TUPLE
13507db96d56Sopenharmony_ci        ):
13517db96d56Sopenharmony_ci            self.items_view(self.traverse, node.elts)
13527db96d56Sopenharmony_ci
13537db96d56Sopenharmony_ci    unop = {"Invert": "~", "Not": "not", "UAdd": "+", "USub": "-"}
13547db96d56Sopenharmony_ci    unop_precedence = {
13557db96d56Sopenharmony_ci        "not": _Precedence.NOT,
13567db96d56Sopenharmony_ci        "~": _Precedence.FACTOR,
13577db96d56Sopenharmony_ci        "+": _Precedence.FACTOR,
13587db96d56Sopenharmony_ci        "-": _Precedence.FACTOR,
13597db96d56Sopenharmony_ci    }
13607db96d56Sopenharmony_ci
13617db96d56Sopenharmony_ci    def visit_UnaryOp(self, node):
13627db96d56Sopenharmony_ci        operator = self.unop[node.op.__class__.__name__]
13637db96d56Sopenharmony_ci        operator_precedence = self.unop_precedence[operator]
13647db96d56Sopenharmony_ci        with self.require_parens(operator_precedence, node):
13657db96d56Sopenharmony_ci            self.write(operator)
13667db96d56Sopenharmony_ci            # factor prefixes (+, -, ~) shouldn't be separated
13677db96d56Sopenharmony_ci            # from the value they belong, (e.g: +1 instead of + 1)
13687db96d56Sopenharmony_ci            if operator_precedence is not _Precedence.FACTOR:
13697db96d56Sopenharmony_ci                self.write(" ")
13707db96d56Sopenharmony_ci            self.set_precedence(operator_precedence, node.operand)
13717db96d56Sopenharmony_ci            self.traverse(node.operand)
13727db96d56Sopenharmony_ci
13737db96d56Sopenharmony_ci    binop = {
13747db96d56Sopenharmony_ci        "Add": "+",
13757db96d56Sopenharmony_ci        "Sub": "-",
13767db96d56Sopenharmony_ci        "Mult": "*",
13777db96d56Sopenharmony_ci        "MatMult": "@",
13787db96d56Sopenharmony_ci        "Div": "/",
13797db96d56Sopenharmony_ci        "Mod": "%",
13807db96d56Sopenharmony_ci        "LShift": "<<",
13817db96d56Sopenharmony_ci        "RShift": ">>",
13827db96d56Sopenharmony_ci        "BitOr": "|",
13837db96d56Sopenharmony_ci        "BitXor": "^",
13847db96d56Sopenharmony_ci        "BitAnd": "&",
13857db96d56Sopenharmony_ci        "FloorDiv": "//",
13867db96d56Sopenharmony_ci        "Pow": "**",
13877db96d56Sopenharmony_ci    }
13887db96d56Sopenharmony_ci
13897db96d56Sopenharmony_ci    binop_precedence = {
13907db96d56Sopenharmony_ci        "+": _Precedence.ARITH,
13917db96d56Sopenharmony_ci        "-": _Precedence.ARITH,
13927db96d56Sopenharmony_ci        "*": _Precedence.TERM,
13937db96d56Sopenharmony_ci        "@": _Precedence.TERM,
13947db96d56Sopenharmony_ci        "/": _Precedence.TERM,
13957db96d56Sopenharmony_ci        "%": _Precedence.TERM,
13967db96d56Sopenharmony_ci        "<<": _Precedence.SHIFT,
13977db96d56Sopenharmony_ci        ">>": _Precedence.SHIFT,
13987db96d56Sopenharmony_ci        "|": _Precedence.BOR,
13997db96d56Sopenharmony_ci        "^": _Precedence.BXOR,
14007db96d56Sopenharmony_ci        "&": _Precedence.BAND,
14017db96d56Sopenharmony_ci        "//": _Precedence.TERM,
14027db96d56Sopenharmony_ci        "**": _Precedence.POWER,
14037db96d56Sopenharmony_ci    }
14047db96d56Sopenharmony_ci
14057db96d56Sopenharmony_ci    binop_rassoc = frozenset(("**",))
14067db96d56Sopenharmony_ci    def visit_BinOp(self, node):
14077db96d56Sopenharmony_ci        operator = self.binop[node.op.__class__.__name__]
14087db96d56Sopenharmony_ci        operator_precedence = self.binop_precedence[operator]
14097db96d56Sopenharmony_ci        with self.require_parens(operator_precedence, node):
14107db96d56Sopenharmony_ci            if operator in self.binop_rassoc:
14117db96d56Sopenharmony_ci                left_precedence = operator_precedence.next()
14127db96d56Sopenharmony_ci                right_precedence = operator_precedence
14137db96d56Sopenharmony_ci            else:
14147db96d56Sopenharmony_ci                left_precedence = operator_precedence
14157db96d56Sopenharmony_ci                right_precedence = operator_precedence.next()
14167db96d56Sopenharmony_ci
14177db96d56Sopenharmony_ci            self.set_precedence(left_precedence, node.left)
14187db96d56Sopenharmony_ci            self.traverse(node.left)
14197db96d56Sopenharmony_ci            self.write(f" {operator} ")
14207db96d56Sopenharmony_ci            self.set_precedence(right_precedence, node.right)
14217db96d56Sopenharmony_ci            self.traverse(node.right)
14227db96d56Sopenharmony_ci
14237db96d56Sopenharmony_ci    cmpops = {
14247db96d56Sopenharmony_ci        "Eq": "==",
14257db96d56Sopenharmony_ci        "NotEq": "!=",
14267db96d56Sopenharmony_ci        "Lt": "<",
14277db96d56Sopenharmony_ci        "LtE": "<=",
14287db96d56Sopenharmony_ci        "Gt": ">",
14297db96d56Sopenharmony_ci        "GtE": ">=",
14307db96d56Sopenharmony_ci        "Is": "is",
14317db96d56Sopenharmony_ci        "IsNot": "is not",
14327db96d56Sopenharmony_ci        "In": "in",
14337db96d56Sopenharmony_ci        "NotIn": "not in",
14347db96d56Sopenharmony_ci    }
14357db96d56Sopenharmony_ci
14367db96d56Sopenharmony_ci    def visit_Compare(self, node):
14377db96d56Sopenharmony_ci        with self.require_parens(_Precedence.CMP, node):
14387db96d56Sopenharmony_ci            self.set_precedence(_Precedence.CMP.next(), node.left, *node.comparators)
14397db96d56Sopenharmony_ci            self.traverse(node.left)
14407db96d56Sopenharmony_ci            for o, e in zip(node.ops, node.comparators):
14417db96d56Sopenharmony_ci                self.write(" " + self.cmpops[o.__class__.__name__] + " ")
14427db96d56Sopenharmony_ci                self.traverse(e)
14437db96d56Sopenharmony_ci
14447db96d56Sopenharmony_ci    boolops = {"And": "and", "Or": "or"}
14457db96d56Sopenharmony_ci    boolop_precedence = {"and": _Precedence.AND, "or": _Precedence.OR}
14467db96d56Sopenharmony_ci
14477db96d56Sopenharmony_ci    def visit_BoolOp(self, node):
14487db96d56Sopenharmony_ci        operator = self.boolops[node.op.__class__.__name__]
14497db96d56Sopenharmony_ci        operator_precedence = self.boolop_precedence[operator]
14507db96d56Sopenharmony_ci
14517db96d56Sopenharmony_ci        def increasing_level_traverse(node):
14527db96d56Sopenharmony_ci            nonlocal operator_precedence
14537db96d56Sopenharmony_ci            operator_precedence = operator_precedence.next()
14547db96d56Sopenharmony_ci            self.set_precedence(operator_precedence, node)
14557db96d56Sopenharmony_ci            self.traverse(node)
14567db96d56Sopenharmony_ci
14577db96d56Sopenharmony_ci        with self.require_parens(operator_precedence, node):
14587db96d56Sopenharmony_ci            s = f" {operator} "
14597db96d56Sopenharmony_ci            self.interleave(lambda: self.write(s), increasing_level_traverse, node.values)
14607db96d56Sopenharmony_ci
14617db96d56Sopenharmony_ci    def visit_Attribute(self, node):
14627db96d56Sopenharmony_ci        self.set_precedence(_Precedence.ATOM, node.value)
14637db96d56Sopenharmony_ci        self.traverse(node.value)
14647db96d56Sopenharmony_ci        # Special case: 3.__abs__() is a syntax error, so if node.value
14657db96d56Sopenharmony_ci        # is an integer literal then we need to either parenthesize
14667db96d56Sopenharmony_ci        # it or add an extra space to get 3 .__abs__().
14677db96d56Sopenharmony_ci        if isinstance(node.value, Constant) and isinstance(node.value.value, int):
14687db96d56Sopenharmony_ci            self.write(" ")
14697db96d56Sopenharmony_ci        self.write(".")
14707db96d56Sopenharmony_ci        self.write(node.attr)
14717db96d56Sopenharmony_ci
14727db96d56Sopenharmony_ci    def visit_Call(self, node):
14737db96d56Sopenharmony_ci        self.set_precedence(_Precedence.ATOM, node.func)
14747db96d56Sopenharmony_ci        self.traverse(node.func)
14757db96d56Sopenharmony_ci        with self.delimit("(", ")"):
14767db96d56Sopenharmony_ci            comma = False
14777db96d56Sopenharmony_ci            for e in node.args:
14787db96d56Sopenharmony_ci                if comma:
14797db96d56Sopenharmony_ci                    self.write(", ")
14807db96d56Sopenharmony_ci                else:
14817db96d56Sopenharmony_ci                    comma = True
14827db96d56Sopenharmony_ci                self.traverse(e)
14837db96d56Sopenharmony_ci            for e in node.keywords:
14847db96d56Sopenharmony_ci                if comma:
14857db96d56Sopenharmony_ci                    self.write(", ")
14867db96d56Sopenharmony_ci                else:
14877db96d56Sopenharmony_ci                    comma = True
14887db96d56Sopenharmony_ci                self.traverse(e)
14897db96d56Sopenharmony_ci
14907db96d56Sopenharmony_ci    def visit_Subscript(self, node):
14917db96d56Sopenharmony_ci        def is_non_empty_tuple(slice_value):
14927db96d56Sopenharmony_ci            return (
14937db96d56Sopenharmony_ci                isinstance(slice_value, Tuple)
14947db96d56Sopenharmony_ci                and slice_value.elts
14957db96d56Sopenharmony_ci            )
14967db96d56Sopenharmony_ci
14977db96d56Sopenharmony_ci        self.set_precedence(_Precedence.ATOM, node.value)
14987db96d56Sopenharmony_ci        self.traverse(node.value)
14997db96d56Sopenharmony_ci        with self.delimit("[", "]"):
15007db96d56Sopenharmony_ci            if is_non_empty_tuple(node.slice):
15017db96d56Sopenharmony_ci                # parentheses can be omitted if the tuple isn't empty
15027db96d56Sopenharmony_ci                self.items_view(self.traverse, node.slice.elts)
15037db96d56Sopenharmony_ci            else:
15047db96d56Sopenharmony_ci                self.traverse(node.slice)
15057db96d56Sopenharmony_ci
15067db96d56Sopenharmony_ci    def visit_Starred(self, node):
15077db96d56Sopenharmony_ci        self.write("*")
15087db96d56Sopenharmony_ci        self.set_precedence(_Precedence.EXPR, node.value)
15097db96d56Sopenharmony_ci        self.traverse(node.value)
15107db96d56Sopenharmony_ci
15117db96d56Sopenharmony_ci    def visit_Ellipsis(self, node):
15127db96d56Sopenharmony_ci        self.write("...")
15137db96d56Sopenharmony_ci
15147db96d56Sopenharmony_ci    def visit_Slice(self, node):
15157db96d56Sopenharmony_ci        if node.lower:
15167db96d56Sopenharmony_ci            self.traverse(node.lower)
15177db96d56Sopenharmony_ci        self.write(":")
15187db96d56Sopenharmony_ci        if node.upper:
15197db96d56Sopenharmony_ci            self.traverse(node.upper)
15207db96d56Sopenharmony_ci        if node.step:
15217db96d56Sopenharmony_ci            self.write(":")
15227db96d56Sopenharmony_ci            self.traverse(node.step)
15237db96d56Sopenharmony_ci
15247db96d56Sopenharmony_ci    def visit_Match(self, node):
15257db96d56Sopenharmony_ci        self.fill("match ")
15267db96d56Sopenharmony_ci        self.traverse(node.subject)
15277db96d56Sopenharmony_ci        with self.block():
15287db96d56Sopenharmony_ci            for case in node.cases:
15297db96d56Sopenharmony_ci                self.traverse(case)
15307db96d56Sopenharmony_ci
15317db96d56Sopenharmony_ci    def visit_arg(self, node):
15327db96d56Sopenharmony_ci        self.write(node.arg)
15337db96d56Sopenharmony_ci        if node.annotation:
15347db96d56Sopenharmony_ci            self.write(": ")
15357db96d56Sopenharmony_ci            self.traverse(node.annotation)
15367db96d56Sopenharmony_ci
15377db96d56Sopenharmony_ci    def visit_arguments(self, node):
15387db96d56Sopenharmony_ci        first = True
15397db96d56Sopenharmony_ci        # normal arguments
15407db96d56Sopenharmony_ci        all_args = node.posonlyargs + node.args
15417db96d56Sopenharmony_ci        defaults = [None] * (len(all_args) - len(node.defaults)) + node.defaults
15427db96d56Sopenharmony_ci        for index, elements in enumerate(zip(all_args, defaults), 1):
15437db96d56Sopenharmony_ci            a, d = elements
15447db96d56Sopenharmony_ci            if first:
15457db96d56Sopenharmony_ci                first = False
15467db96d56Sopenharmony_ci            else:
15477db96d56Sopenharmony_ci                self.write(", ")
15487db96d56Sopenharmony_ci            self.traverse(a)
15497db96d56Sopenharmony_ci            if d:
15507db96d56Sopenharmony_ci                self.write("=")
15517db96d56Sopenharmony_ci                self.traverse(d)
15527db96d56Sopenharmony_ci            if index == len(node.posonlyargs):
15537db96d56Sopenharmony_ci                self.write(", /")
15547db96d56Sopenharmony_ci
15557db96d56Sopenharmony_ci        # varargs, or bare '*' if no varargs but keyword-only arguments present
15567db96d56Sopenharmony_ci        if node.vararg or node.kwonlyargs:
15577db96d56Sopenharmony_ci            if first:
15587db96d56Sopenharmony_ci                first = False
15597db96d56Sopenharmony_ci            else:
15607db96d56Sopenharmony_ci                self.write(", ")
15617db96d56Sopenharmony_ci            self.write("*")
15627db96d56Sopenharmony_ci            if node.vararg:
15637db96d56Sopenharmony_ci                self.write(node.vararg.arg)
15647db96d56Sopenharmony_ci                if node.vararg.annotation:
15657db96d56Sopenharmony_ci                    self.write(": ")
15667db96d56Sopenharmony_ci                    self.traverse(node.vararg.annotation)
15677db96d56Sopenharmony_ci
15687db96d56Sopenharmony_ci        # keyword-only arguments
15697db96d56Sopenharmony_ci        if node.kwonlyargs:
15707db96d56Sopenharmony_ci            for a, d in zip(node.kwonlyargs, node.kw_defaults):
15717db96d56Sopenharmony_ci                self.write(", ")
15727db96d56Sopenharmony_ci                self.traverse(a)
15737db96d56Sopenharmony_ci                if d:
15747db96d56Sopenharmony_ci                    self.write("=")
15757db96d56Sopenharmony_ci                    self.traverse(d)
15767db96d56Sopenharmony_ci
15777db96d56Sopenharmony_ci        # kwargs
15787db96d56Sopenharmony_ci        if node.kwarg:
15797db96d56Sopenharmony_ci            if first:
15807db96d56Sopenharmony_ci                first = False
15817db96d56Sopenharmony_ci            else:
15827db96d56Sopenharmony_ci                self.write(", ")
15837db96d56Sopenharmony_ci            self.write("**" + node.kwarg.arg)
15847db96d56Sopenharmony_ci            if node.kwarg.annotation:
15857db96d56Sopenharmony_ci                self.write(": ")
15867db96d56Sopenharmony_ci                self.traverse(node.kwarg.annotation)
15877db96d56Sopenharmony_ci
15887db96d56Sopenharmony_ci    def visit_keyword(self, node):
15897db96d56Sopenharmony_ci        if node.arg is None:
15907db96d56Sopenharmony_ci            self.write("**")
15917db96d56Sopenharmony_ci        else:
15927db96d56Sopenharmony_ci            self.write(node.arg)
15937db96d56Sopenharmony_ci            self.write("=")
15947db96d56Sopenharmony_ci        self.traverse(node.value)
15957db96d56Sopenharmony_ci
15967db96d56Sopenharmony_ci    def visit_Lambda(self, node):
15977db96d56Sopenharmony_ci        with self.require_parens(_Precedence.TEST, node):
15987db96d56Sopenharmony_ci            self.write("lambda")
15997db96d56Sopenharmony_ci            with self.buffered() as buffer:
16007db96d56Sopenharmony_ci                self.traverse(node.args)
16017db96d56Sopenharmony_ci            if buffer:
16027db96d56Sopenharmony_ci                self.write(" ", *buffer)
16037db96d56Sopenharmony_ci            self.write(": ")
16047db96d56Sopenharmony_ci            self.set_precedence(_Precedence.TEST, node.body)
16057db96d56Sopenharmony_ci            self.traverse(node.body)
16067db96d56Sopenharmony_ci
16077db96d56Sopenharmony_ci    def visit_alias(self, node):
16087db96d56Sopenharmony_ci        self.write(node.name)
16097db96d56Sopenharmony_ci        if node.asname:
16107db96d56Sopenharmony_ci            self.write(" as " + node.asname)
16117db96d56Sopenharmony_ci
16127db96d56Sopenharmony_ci    def visit_withitem(self, node):
16137db96d56Sopenharmony_ci        self.traverse(node.context_expr)
16147db96d56Sopenharmony_ci        if node.optional_vars:
16157db96d56Sopenharmony_ci            self.write(" as ")
16167db96d56Sopenharmony_ci            self.traverse(node.optional_vars)
16177db96d56Sopenharmony_ci
16187db96d56Sopenharmony_ci    def visit_match_case(self, node):
16197db96d56Sopenharmony_ci        self.fill("case ")
16207db96d56Sopenharmony_ci        self.traverse(node.pattern)
16217db96d56Sopenharmony_ci        if node.guard:
16227db96d56Sopenharmony_ci            self.write(" if ")
16237db96d56Sopenharmony_ci            self.traverse(node.guard)
16247db96d56Sopenharmony_ci        with self.block():
16257db96d56Sopenharmony_ci            self.traverse(node.body)
16267db96d56Sopenharmony_ci
16277db96d56Sopenharmony_ci    def visit_MatchValue(self, node):
16287db96d56Sopenharmony_ci        self.traverse(node.value)
16297db96d56Sopenharmony_ci
16307db96d56Sopenharmony_ci    def visit_MatchSingleton(self, node):
16317db96d56Sopenharmony_ci        self._write_constant(node.value)
16327db96d56Sopenharmony_ci
16337db96d56Sopenharmony_ci    def visit_MatchSequence(self, node):
16347db96d56Sopenharmony_ci        with self.delimit("[", "]"):
16357db96d56Sopenharmony_ci            self.interleave(
16367db96d56Sopenharmony_ci                lambda: self.write(", "), self.traverse, node.patterns
16377db96d56Sopenharmony_ci            )
16387db96d56Sopenharmony_ci
16397db96d56Sopenharmony_ci    def visit_MatchStar(self, node):
16407db96d56Sopenharmony_ci        name = node.name
16417db96d56Sopenharmony_ci        if name is None:
16427db96d56Sopenharmony_ci            name = "_"
16437db96d56Sopenharmony_ci        self.write(f"*{name}")
16447db96d56Sopenharmony_ci
16457db96d56Sopenharmony_ci    def visit_MatchMapping(self, node):
16467db96d56Sopenharmony_ci        def write_key_pattern_pair(pair):
16477db96d56Sopenharmony_ci            k, p = pair
16487db96d56Sopenharmony_ci            self.traverse(k)
16497db96d56Sopenharmony_ci            self.write(": ")
16507db96d56Sopenharmony_ci            self.traverse(p)
16517db96d56Sopenharmony_ci
16527db96d56Sopenharmony_ci        with self.delimit("{", "}"):
16537db96d56Sopenharmony_ci            keys = node.keys
16547db96d56Sopenharmony_ci            self.interleave(
16557db96d56Sopenharmony_ci                lambda: self.write(", "),
16567db96d56Sopenharmony_ci                write_key_pattern_pair,
16577db96d56Sopenharmony_ci                zip(keys, node.patterns, strict=True),
16587db96d56Sopenharmony_ci            )
16597db96d56Sopenharmony_ci            rest = node.rest
16607db96d56Sopenharmony_ci            if rest is not None:
16617db96d56Sopenharmony_ci                if keys:
16627db96d56Sopenharmony_ci                    self.write(", ")
16637db96d56Sopenharmony_ci                self.write(f"**{rest}")
16647db96d56Sopenharmony_ci
16657db96d56Sopenharmony_ci    def visit_MatchClass(self, node):
16667db96d56Sopenharmony_ci        self.set_precedence(_Precedence.ATOM, node.cls)
16677db96d56Sopenharmony_ci        self.traverse(node.cls)
16687db96d56Sopenharmony_ci        with self.delimit("(", ")"):
16697db96d56Sopenharmony_ci            patterns = node.patterns
16707db96d56Sopenharmony_ci            self.interleave(
16717db96d56Sopenharmony_ci                lambda: self.write(", "), self.traverse, patterns
16727db96d56Sopenharmony_ci            )
16737db96d56Sopenharmony_ci            attrs = node.kwd_attrs
16747db96d56Sopenharmony_ci            if attrs:
16757db96d56Sopenharmony_ci                def write_attr_pattern(pair):
16767db96d56Sopenharmony_ci                    attr, pattern = pair
16777db96d56Sopenharmony_ci                    self.write(f"{attr}=")
16787db96d56Sopenharmony_ci                    self.traverse(pattern)
16797db96d56Sopenharmony_ci
16807db96d56Sopenharmony_ci                if patterns:
16817db96d56Sopenharmony_ci                    self.write(", ")
16827db96d56Sopenharmony_ci                self.interleave(
16837db96d56Sopenharmony_ci                    lambda: self.write(", "),
16847db96d56Sopenharmony_ci                    write_attr_pattern,
16857db96d56Sopenharmony_ci                    zip(attrs, node.kwd_patterns, strict=True),
16867db96d56Sopenharmony_ci                )
16877db96d56Sopenharmony_ci
16887db96d56Sopenharmony_ci    def visit_MatchAs(self, node):
16897db96d56Sopenharmony_ci        name = node.name
16907db96d56Sopenharmony_ci        pattern = node.pattern
16917db96d56Sopenharmony_ci        if name is None:
16927db96d56Sopenharmony_ci            self.write("_")
16937db96d56Sopenharmony_ci        elif pattern is None:
16947db96d56Sopenharmony_ci            self.write(node.name)
16957db96d56Sopenharmony_ci        else:
16967db96d56Sopenharmony_ci            with self.require_parens(_Precedence.TEST, node):
16977db96d56Sopenharmony_ci                self.set_precedence(_Precedence.BOR, node.pattern)
16987db96d56Sopenharmony_ci                self.traverse(node.pattern)
16997db96d56Sopenharmony_ci                self.write(f" as {node.name}")
17007db96d56Sopenharmony_ci
17017db96d56Sopenharmony_ci    def visit_MatchOr(self, node):
17027db96d56Sopenharmony_ci        with self.require_parens(_Precedence.BOR, node):
17037db96d56Sopenharmony_ci            self.set_precedence(_Precedence.BOR.next(), *node.patterns)
17047db96d56Sopenharmony_ci            self.interleave(lambda: self.write(" | "), self.traverse, node.patterns)
17057db96d56Sopenharmony_ci
17067db96d56Sopenharmony_cidef unparse(ast_obj):
17077db96d56Sopenharmony_ci    unparser = _Unparser()
17087db96d56Sopenharmony_ci    return unparser.visit(ast_obj)
17097db96d56Sopenharmony_ci
17107db96d56Sopenharmony_ci
17117db96d56Sopenharmony_cidef main():
17127db96d56Sopenharmony_ci    import argparse
17137db96d56Sopenharmony_ci
17147db96d56Sopenharmony_ci    parser = argparse.ArgumentParser(prog='python -m ast')
17157db96d56Sopenharmony_ci    parser.add_argument('infile', type=argparse.FileType(mode='rb'), nargs='?',
17167db96d56Sopenharmony_ci                        default='-',
17177db96d56Sopenharmony_ci                        help='the file to parse; defaults to stdin')
17187db96d56Sopenharmony_ci    parser.add_argument('-m', '--mode', default='exec',
17197db96d56Sopenharmony_ci                        choices=('exec', 'single', 'eval', 'func_type'),
17207db96d56Sopenharmony_ci                        help='specify what kind of code must be parsed')
17217db96d56Sopenharmony_ci    parser.add_argument('--no-type-comments', default=True, action='store_false',
17227db96d56Sopenharmony_ci                        help="don't add information about type comments")
17237db96d56Sopenharmony_ci    parser.add_argument('-a', '--include-attributes', action='store_true',
17247db96d56Sopenharmony_ci                        help='include attributes such as line numbers and '
17257db96d56Sopenharmony_ci                             'column offsets')
17267db96d56Sopenharmony_ci    parser.add_argument('-i', '--indent', type=int, default=3,
17277db96d56Sopenharmony_ci                        help='indentation of nodes (number of spaces)')
17287db96d56Sopenharmony_ci    args = parser.parse_args()
17297db96d56Sopenharmony_ci
17307db96d56Sopenharmony_ci    with args.infile as infile:
17317db96d56Sopenharmony_ci        source = infile.read()
17327db96d56Sopenharmony_ci    tree = parse(source, args.infile.name, args.mode, type_comments=args.no_type_comments)
17337db96d56Sopenharmony_ci    print(dump(tree, include_attributes=args.include_attributes, indent=args.indent))
17347db96d56Sopenharmony_ci
17357db96d56Sopenharmony_ciif __name__ == '__main__':
17367db96d56Sopenharmony_ci    main()
1737