File: node.py

package info (click to toggle)
python-tatsu 5.17.1%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,516 kB
  • sloc: python: 13,185; makefile: 127
file content (88 lines) | stat: -rw-r--r-- 2,596 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# Copyright (c) 2017-2026 Juancarlo AƱez (apalala@gmail.com)
# SPDX-License-Identifier: BSD-4-Clause
from __future__ import annotations

import functools
import weakref
from collections.abc import Iterable, Mapping
from typing import Any

from .basenode import BaseNode, tatsudataclass

__all__ = ['Node', 'tatsudataclass']

from ..util.deprecate import deprecated


@tatsudataclass
class Node(BaseNode):
    def __init__(self, ast: Any = None, **kwargs: Any):
        super().__init__(ast=ast, **kwargs)
        self.__parent_ref: weakref.ref[Node] | None = (  # pyright: ignore[reportRedeclaration]
            None
        )

    def __post_init__(self):
        super().__post_init__()
        self.__parent_ref: weakref.ref[Node] | None = None

    @property
    def parent(self) -> Node | None:
        ref = self.__parent_ref
        if ref is None:
            return None
        else:
            return ref()

    @property
    def comments(self) -> Any:
        deprecated(replacement=None)(self.comments)
        return None

    @property
    def text(self) -> str | None:
        pi = self.parseinfo
        if pi and hasattr(pi.tokenizer, "text"):
            return pi.tokenizer.text[pi.pos : pi.endpos]
        return None

    @property
    def line(self) -> int | None:
        return self.parseinfo.line if self.parseinfo else None

    @property
    def path(self) -> tuple[Node, ...]:
        ancestors: list[Node] = [self]
        parent = self.parent
        while parent is not None:
            ancestors.append(parent)
            parent = parent.parent
        return tuple(reversed(ancestors))

    def children(self) -> tuple[Node, ...]:
        return self._cached_children

    def children_list(self) -> list[Node]:
        return list(self._cached_children)

    @functools.cached_property
    def _cached_children(self) -> tuple[Node, ...]:
        def dfs(obj: Any) -> Iterable[Node]:
            match obj:
                case Node() as node:
                    node.__parent_ref = weakref.ref(self)
                    yield node
                case Mapping() as map:
                    for name, value in map.items():
                        if name.startswith("_"):
                            continue
                        if value is None:
                            continue
                        yield from dfs(value)
                case (list() | tuple()) as seq:
                    for item in seq:
                        yield from dfs(item)
                case _:
                    pass

        return tuple(dfs(self.__pub__()))